diff --git a/.hgtags b/.hgtags index 3fe829ce922..5cfc1c804be 100644 --- a/.hgtags +++ b/.hgtags @@ -82,3 +82,7 @@ c4c8a5bc54f66abc68cd185d9294042121922154 jdk7-b99 1ce7938efb03224ccc8b3cdd7803eb39e889539c jdk7-b105 6bdae472f77205046703b685eff2ac4f7a0ecf4e jdk7-b106 439de530aac531a360beedba6e2fe51e17292cc0 jdk7-b107 +044d31b99ef5609389fc771c422e722e5e224228 jdk7-b108 +e02b4d709e177d08d56130a4bc68061e4bbacc7d jdk7-b109 +a6442d6bc38a44152e0662688213ce4d2701f42a jdk7-b110 +69f3edf083477955b5bd2f754252c7504167d8e1 jdk7-b111 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index c533bdc1115..19a3f1c2601 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -82,3 +82,7 @@ f8be576feefce0c6695f188ef97ec16b73ad9cfd jdk7-b104 9f96a4269d7727dad68864eaab795eafce270311 jdk7-b105 43096cccf1cee749c2f4e7714ee71f4e9e0f4d7f jdk7-b106 7d396ad455c3b2f68b0d7094891c5aba7c757a6e jdk7-b107 +140fdef4ddf52244013b6157dc542cd9f677bb6f jdk7-b108 +81dfc728d7bb7e1fff4a4dc6d0f7cea5a3315667 jdk7-b109 +2a02d4a6955c7c078aee9a604cb3be409800d82c jdk7-b110 +9702d6fef68e17533ee7fcf5923b11ead3e912ce jdk7-b111 diff --git a/README-builds.html b/README-builds.html index 00b8612911d..81ada58e303 100644 --- a/README-builds.html +++ b/README-builds.html @@ -148,7 +148,7 @@ See SunSolve for patch downloads. - Sun Studio 12 + Sun Studio 12 Update 1 + patches JDK 6u14 FCS @@ -158,7 +158,7 @@ See SunSolve for patch downloads. - Sun Studio 12 + Sun Studio 12 Update 1 + patches JDK 6u14 FCS @@ -168,7 +168,7 @@ See SunSolve for patch downloads. - Sun Studio 12 + Sun Studio 12 Update 1 + patches JDK 6u14 FCS @@ -178,7 +178,7 @@ See SunSolve for patch downloads. - Sun Studio 12 + Sun Studio 12 Update 1 + patches JDK 6u14 FCS @@ -941,21 +941,78 @@ Solaris: Sun Studio
At a minimum, the - - Sun Studio 12 Compilers - (containing version 5.9 of the C and C++ compilers) is required, - with patches from the - - SunSolve web site. + + Sun Studio 12 Update 1 Compilers + (containing version 5.10 of the C and C++ compilers) is required, + including specific patches. +

+ The Solaris SPARC patch list is: +

+

+ The Solaris X86 patch list is: +

Set ALT_COMPILER_PATH to point to the location of the compiler binaries, and place this location in the PATH.

- The Sun Studio Express compilers at: + The Oracle Solaris Studio Express compilers at: - Sun Studio Express Download site + Oracle Solaris Studio Express Download site are also an option, although these compilers have not been extensively used yet.

diff --git a/corba/.hgtags b/corba/.hgtags index 6eac1b642e0..9f6d3054114 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -82,3 +82,7 @@ a56d734a1e970e1a21a8f4feb13053e9a33674c7 jdk7-b100 6f21b030092fb61244cc8a0aedf8058f7c022b81 jdk7-b105 519daea48888196af76a975a3b31258efa860bad jdk7-b106 232adb83eae8375439ccff65b6e205ca0da0510d jdk7-b107 +8d810527b499a67153365db74421a03c12b46f35 jdk7-b108 +c3dd858e09b20206459d9e7b0ead99d27ab00eab jdk7-b109 +0e1f80fda2271f53d4bbb59ec3f301dfbcef6a0a jdk7-b110 +640fa4d4e2ad4c2d7e4815c955026740d8c52b7a jdk7-b111 diff --git a/corba/make/Makefile b/corba/make/Makefile index 8501686c411..b8a71915079 100644 --- a/corba/make/Makefile +++ b/corba/make/Makefile @@ -61,7 +61,6 @@ ABS_OUTPUTDIR = $(call FullPath,$(OUTPUTDIR)) CLASSES_DIR = $(BUILD_DIR)/classes GENSRC_DIR = $(BUILD_DIR)/gensrc -BIN_DIR = $(DIST_DIR)/bin LIB_DIR = $(DIST_DIR)/lib #----- diff --git a/corba/make/common/Defs-linux.gmk b/corba/make/common/Defs-linux.gmk index 785cd205302..a5ef1d36b29 100644 --- a/corba/make/common/Defs-linux.gmk +++ b/corba/make/common/Defs-linux.gmk @@ -28,306 +28,10 @@ # targeted to Linux. Should not contain any rules. # -# Warning: the following variables are overriden by Defs.gmk. Set -# values will be silently ignored: -# CFLAGS (set $(OTHER_CFLAGS) instead) -# CPPFLAGS (set $(OTHER_CPPFLAGS) instead) -# CXXFLAGS (set $(OTHER_CXXFLAGS) instead) -# LDFLAGS (set $(OTHER_LDFAGS) instead) -# LDLIBS (set $(EXTRA_LIBS) instead) -# LDLIBS_COMMON (set $(EXTRA_LIBS) instead) - # Get shared JDK settings include $(BUILDDIR)/common/shared/Defs.gmk -# Part of INCREMENTAL_BUILD mechanism. -# Compiler emits things like: path/file.o: file.h -# We want something like: relative_path/file.o relative_path/file.d: file.h -CC_DEPEND = -MM -CC_DEPEND_FILTER = $(SED) -e 's!$*\.$(OBJECT_SUFFIX)!$(dir $@)& $(dir $@)$*.$(DEPEND_SUFFIX)!g' - ifndef PLATFORM_SRC PLATFORM_SRC = $(TOPDIR)/src/solaris endif # PLATFORM_SRC -# platform specific include files -PLATFORM_INCLUDE_NAME = $(PLATFORM) -PLATFORM_INCLUDE = $(INCLUDEDIR)/$(PLATFORM_INCLUDE_NAME) - -# suffix used for make dependencies files. -DEPEND_SUFFIX = d -# The suffix applied to the library name for FDLIBM -FDDLIBM_SUFFIX = a -# The suffix applied to scripts (.bat for windows, nothing for unix) -SCRIPT_SUFFIX = -# CC compiler object code output directive flag value -CC_OBJECT_OUTPUT_FLAG = -o #trailing blank required! -CC_PROGRAM_OUTPUT_FLAG = -o #trailing blank required! - -# -# Default HPI libraries. Build will build only native, unless -# overriden at the make command line. This makes it convenient for -# people doing, say, a pthreads port -- they can create a posix -# directory here, and say "gnumake HPIS=posix" at the top -# level. -# -HPIS = native - -# -# Default optimization -# -CC_HIGHEST_OPT = -O3 -CC_HIGHER_OPT = -O3 -CC_LOWER_OPT = -O2 -CC_NO_OPT = - -ifeq ($(PRODUCT), java) - _OPT = $(CC_HIGHER_OPT) -else - _OPT = $(CC_LOWER_OPT) - CPPFLAGS_DBG += -DLOGGING -endif - -# For all platforms, do not omit the frame pointer register usage. -# We need this frame pointer to make it easy to walk the stacks. -# This should be the default on X86, but ia64 and amd64 may not have this -# as the default. -CFLAGS_REQUIRED_amd64 += -fno-omit-frame-pointer -D_LITTLE_ENDIAN -CFLAGS_REQUIRED_i586 += -fno-omit-frame-pointer -D_LITTLE_ENDIAN -CFLAGS_REQUIRED_ia64 += -fno-omit-frame-pointer -D_LITTLE_ENDIAN -CFLAGS_REQUIRED_sparcv9 += -m64 -mcpu=v9 -LDFLAGS_COMMON_sparcv9 += -m64 -mcpu=v9 -CFLAGS_REQUIRED_sparc += -m32 -mcpu=v9 -LDFLAGS_COMMON_sparc += -m32 -mcpu=v9 -ifeq ($(ZERO_BUILD), true) - CFLAGS_REQUIRED = $(ZERO_ARCHFLAG) - ifeq ($(ZERO_ENDIANNESS), little) - CFLAGS_REQUIRED += -D_LITTLE_ENDIAN - endif - LDFLAGS_COMMON += $(ZERO_ARCHFLAG) -else - CFLAGS_REQUIRED = $(CFLAGS_REQUIRED_$(ARCH)) - LDFLAGS_COMMON += $(LDFLAGS_COMMON_$(ARCH)) -endif - -# Add in platform specific optimizations for all opt levels -CC_HIGHEST_OPT += $(_OPT_$(ARCH)) -CC_HIGHER_OPT += $(_OPT_$(ARCH)) -CC_LOWER_OPT += $(_OPT_$(ARCH)) - -# If NO_OPTIMIZATIONS is defined in the environment, turn all optimzations off -ifdef NO_OPTIMIZATIONS - CC_HIGHEST_OPT = $(CC_NO_OPT) - CC_HIGHER_OPT = $(CC_NO_OPT) - CC_LOWER_OPT = $(CC_NO_OPT) -endif - -# -# Selection of warning messages -# -GCC_INHIBIT = -Wno-unused -Wno-parentheses -GCC_STYLE = -GCC_WARNINGS = -W -Wall $(GCC_STYLE) $(GCC_INHIBIT) - -# -# Treat compiler warnings as errors, if warnings not allowed -# -ifeq ($(COMPILER_WARNINGS_FATAL),true) - GCC_WARNINGS += -Werror -endif - -# -# Misc compiler options -# -ifeq ($(ARCH),ppc) - CFLAGS_COMMON = -fsigned-char -else # ARCH - CFLAGS_COMMON = -fno-strict-aliasing -endif # ARCH -PIC_CODE_LARGE = -fPIC -PIC_CODE_SMALL = -fpic -GLOBAL_KPIC = $(PIC_CODE_LARGE) -ifeq ($(ARCH), amd64) - CFLAGS_COMMON += $(GLOBAL_KPIC) $(GCC_WARNINGS) -pipe -else - CFLAGS_COMMON += $(GLOBAL_KPIC) $(GCC_WARNINGS) -endif - -# Linux 64bit machines use Dwarf2, which can be HUGE, have fastdebug use -g1 -DEBUG_FLAG = -g -ifeq ($(FASTDEBUG), true) - ifeq ($(ARCH_DATA_MODEL), 64) - DEBUG_FLAG = -g1 - endif -endif - -CFLAGS_OPT = $(POPT) -CFLAGS_DBG = $(DEBUG_FLAG) -CFLAGS_COMMON += $(CFLAGS_REQUIRED) - -CXXFLAGS_COMMON = $(GLOBAL_KPIC) -DCC_NOEX $(GCC_WARNINGS) -CXXFLAGS_OPT = $(POPT) -CXXFLAGS_DBG = $(DEBUG_FLAG) -CXXFLAGS_COMMON += $(CFLAGS_REQUIRED) - -# FASTDEBUG: Optimize the code in the -g versions, gives us a faster debug java -ifeq ($(FASTDEBUG), true) - CFLAGS_DBG += $(CC_LOWER_OPT) - CXXFLAGS_DBG += $(CC_LOWER_OPT) -endif - -CPP_ARCH_FLAGS = -DARCH='"$(ARCH)"' - -# Alpha arch does not like "alpha" defined (potential general arch cleanup issue here) -ifneq ($(ARCH),alpha) - CPP_ARCH_FLAGS += -D$(ARCH) -else - CPP_ARCH_FLAGS += -D_$(ARCH)_ -endif - -CPPFLAGS_COMMON = $(CPP_ARCH_FLAGS) -DLINUX $(VERSION_DEFINES) \ - -D_LARGEFILE64_SOURCE -D_GNU_SOURCE -D_REENTRANT - -ifeq ($(ARCH_DATA_MODEL), 64) -CPPFLAGS_COMMON += -D_LP64=1 -endif - -CPPFLAGS_OPT = -CPPFLAGS_DBG = -DDEBUG - -ifdef LIBRARY - # Libraries need to locate other libraries at runtime, and you can tell - # a library where to look by way of the dynamic runpaths (RPATH or RUNPATH) - # buried inside the .so. The $ORIGIN says to look relative to where - # the library itself is and it can be followed with relative paths from - # that. By default we always look in $ORIGIN, optionally we add relative - # paths if the Makefile sets LD_RUNPATH_EXTRAS to those relative paths. - # On Linux we add a flag -z origin, not sure if this is necessary, but - # doesn't seem to hurt. - # The environment variable LD_LIBRARY_PATH will over-ride these runpaths. - # Try: 'readelf -d lib*.so' to see these settings in a library. - # - LDFLAGS_COMMON += -Xlinker -z -Xlinker origin -Xlinker -rpath -Xlinker \$$ORIGIN - LDFLAGS_COMMON += $(LD_RUNPATH_EXTRAS:%=-Xlinker -z -Xlinker origin -Xlinker -rpath -Xlinker \$$ORIGIN/%) -endif - -EXTRA_LIBS += -lc - -LDFLAGS_DEFS_OPTION = -Xlinker -z -Xlinker defs -LDFLAGS_COMMON += $(LDFLAGS_DEFS_OPTION) - -# -# -L paths for finding and -ljava -# -LDFLAGS_OPT = -Xlinker -O1 -LDFLAGS_COMMON += -L$(LIBDIR)/$(LIBARCH) -LDFLAGS_COMMON += -Wl,-soname=$(LIB_PREFIX)$(LIBRARY).$(LIBRARY_SUFFIX) - -# -# -static-libgcc is a gcc-3 flag to statically link libgcc, gcc-2.9x always -# statically link libgcc but will print a warning with the flag. We don't -# want the warning, so check gcc version first. -# -CC_VER_MAJOR := $(shell $(CC) -dumpversion | $(SED) 's/egcs-//' | $(CUT) -d'.' -f1) -ifeq ("$(CC_VER_MAJOR)", "3") -OTHER_LDFLAGS += -static-libgcc -endif - -# Automatic precompiled header option to use (if COMPILE_APPROACH=batch) -# (See Rules.gmk) The gcc 5 compiler might have an option for this? -AUTOMATIC_PCH_OPTION = - -# -# Post Processing of libraries/executables -# -ifeq ($(VARIANT), OPT) - ifneq ($(NO_STRIP), true) - # Debug 'strip -g' leaves local function Elf symbols (better stack traces) - POST_STRIP_PROCESS = $(STRIP) -g - endif -endif - -# -# Use: ld $(LD_MAPFILE_FLAG) mapfile *.o -# -LD_MAPFILE_FLAG = -Xlinker --version-script -Xlinker - -# -# Support for Quantify. -# -ifdef QUANTIFY -QUANTIFY_CMD = quantify -QUANTIFY_OPTIONS = -cache-dir=/tmp/quantify -always-use-cache-dir=yes -LINK_PRE_CMD = $(QUANTIFY_CMD) $(QUANTIFY_OPTIONS) -endif - -# -# Path and option to link against the VM, if you have to. Note that -# there are libraries that link against only -ljava, but they do get -# -L to the -ljvm, this is because -ljava depends on -ljvm, whereas -# the library itself should not. -# -VM_NAME = server -JVMLIB = -L$(BOOTDIR)/jre/lib/$(LIBARCH)/$(VM_NAME) -ljvm -JAVALIB = -L$(BOOTDIR)/jre/lib/$(LIBARCH) -ljava $(JVMLIB) - -# -# We want to privatize JVM symbols on Solaris. This is so the user can -# write a function called FindClass and this should not override the -# FindClass that is inside the JVM. At this point in time we are not -# concerned with other JNI libraries because we hope that there will -# not be as many clashes there. -# -PRIVATIZE_JVM_SYMBOLS = false - -USE_PTHREADS = true -override ALT_CODESET_KEY = _NL_CTYPE_CODESET_NAME -override AWT_RUNPATH = -override HAVE_ALTZONE = false -override HAVE_FILIOH = false -override HAVE_GETHRTIME = false -override HAVE_GETHRVTIME = false -override HAVE_SIGIGNORE = true -override LEX_LIBRARY = -lfl -ifeq ($(STATIC_CXX),true) -override LIBCXX = -Wl,-Bstatic -lstdc++ -lgcc -Wl,-Bdynamic -else -override LIBCXX = -lstdc++ -endif -override LIBPOSIX4 = -override LIBSOCKET = -override LIBTHREAD = -override MOOT_PRIORITIES = true -override NO_INTERRUPTIBLE_IO = true -override OPENWIN_HOME = /usr/X11R6 -ifeq ($(ARCH), amd64) -override OPENWIN_LIB = $(OPENWIN_HOME)/lib64 -else -override OPENWIN_LIB = $(OPENWIN_HOME)/lib -endif -override OTHER_M4FLAGS = -D__GLIBC__ -DGNU_ASSEMBLER -override SUN_CMM_SUBDIR = -override THREADS_FLAG = native -override USE_GNU_M4 = true -override USING_GNU_TAR = true -override WRITE_LIBVERSION = false - -# USE_EXECNAME forces the launcher to look up argv[0] on $PATH, and put the -# resulting resolved absolute name of the executable in the environment -# variable EXECNAME. That executable name is then used that to locate the -# installation area. -override USE_EXECNAME = true - -# If your platform has DPS, it will have Type1 fonts too, in which case -# it is best to enable DPS support until such time as 2D's rasteriser -# can fully handle Type1 fonts in all cases. Default is "yes". -# HAVE_DPS should only be "no" if the platform has no DPS headers or libs -# DPS (Displayable PostScript) is available on Solaris machines -HAVE_DPS = no - -# -# Japanese manpages -# -JA_SOURCE_ENCODING = eucJP -JA_TARGET_ENCODINGS = eucJP - diff --git a/corba/make/common/Defs-solaris.gmk b/corba/make/common/Defs-solaris.gmk index d7c5a42362c..eb38771dfab 100644 --- a/corba/make/common/Defs-solaris.gmk +++ b/corba/make/common/Defs-solaris.gmk @@ -28,16 +28,6 @@ # targeted to Solaris. Should not contain any rules. # -# Warning: the following variables are overridden by Defs.gmk. Set -# values will be silently ignored: -# CFLAGS (set $(OTHER_CFLAGS) instead) -# CPPFLAGS (set $(OTHER_CPPFLAGS) instead) -# CXXFLAGS (set $(OTHER_CXXFLAGS) instead) -# LDFLAGS (set $(OTHER_LDFAGS) instead) -# LDLIBS (set $(EXTRA_LIBS) instead) -# LDLIBS_COMMON (set $(EXTRA_LIBS) instead) -# LINTFLAGS (set $(OTHER_LINTFLAGS) instead) - # Get shared JDK settings include $(BUILDDIR)/common/shared/Defs.gmk @@ -45,600 +35,3 @@ ifndef PLATFORM_SRC PLATFORM_SRC = $(TOPDIR)/src/solaris endif # PLATFORM_SRC -# platform specific include files -PLATFORM_INCLUDE_NAME = $(PLATFORM) -PLATFORM_INCLUDE = $(INCLUDEDIR)/$(PLATFORM_INCLUDE_NAME) - -# suffix used for make dependencies files -DEPEND_SUFFIX = d -# suffix used for lint files -LINT_SUFFIX = ln -# The suffix applied to the library name for FDLIBM -FDDLIBM_SUFFIX = a -# The suffix applied to scripts (.bat for windows, nothing for unix) -SCRIPT_SUFFIX = -# CC compiler object code output directive flag value -CC_OBJECT_OUTPUT_FLAG = -o #trailing blank required! -CC_PROGRAM_OUTPUT_FLAG = -o #trailing blank required! - -# -# Default HPI libraries. Build will build only native unless -# overriden at the make command line. This makes it convenient for -# people doing, say, a pthreads port -- they can create a posix -# directory here, and say "gnumake HPIS=posix" at the top -# level. -# -HPIS = native - -# -# Java default optimization (-x04/-O2) etc. Applies to the VM. -# -ifeq ($(PRODUCT), java) - _OPT = $(CC_HIGHER_OPT) -else - _OPT = $(CC_LOWER_OPT) - CPPFLAGS_DBG += -DLOGGING -DDBINFO -endif - -# -# If -Xa is in CFLAGS_COMMON it will end up ahead of $(POPT) for the -# optimized build, and that ordering of the flags completely freaks -# out cc. Hence, -Xa is instead in each CFLAGS variant. -# -# The more unusual options to the Sun C compiler: -# -v Stricter type checking, more error checking -# (To turn ALL warnings into fatals, use -errwarn=%all) -# -xstrconst Place string literals and constants in read-only area -# (means you can't write on your string literals) -# -xs Force debug information (stabs) into the .so or a.out -# (makes the library/executable debuggable without the -# .o files needing to be around, but at a space cost) -# -g & -O If you add the -g option to the optimized compiles -# you will get better stack retraces, the code is -# still optimized. This includes a space cost too. -# -xc99=%none Do NOT allow for c99 extensions to be used. -# e.g. declarations must precede statements -# -xCC Allow the C++ style of comments in C: // -# Required with many of the source files. -# -mt Assume multi-threaded (important) -# - -# -# Debug flag for C and C++ compiler -# -CFLAGS_DEBUG_OPTION=-g -CXXFLAGS_DEBUG_OPTION=-g - -# Turn off -g if we are doing tcov build -ifdef TCOV_BUILD - CFLAGS_DEBUG_OPTION= - CXXFLAGS_DEBUG_OPTION= -endif - -# FASTDEBUG: Optimize the -g builds, gives us a faster debug java -# If true adds -O to the debug compiles. This allows for any assert -# tests to remain and debug checking. The resulting code is faster -# but less debuggable. Stack traces are still valid, although only -# approximate line numbers are given. Printing of local variables -# during a debugging session is not possible, but stepping and -# printing of global or static variables should be possible. -# Performance/size of files should be about the same, maybe smaller. -# -ifeq ($(FASTDEBUG), true) - CC_FASTDEBUG_OPT = $(CC_LOWER_OPT) - CFLAGS_DEBUG_OPTION = -g $(CC_FASTDEBUG_OPT) - CXXFLAGS_DEBUG_OPTION = -g0 $(CC_FASTDEBUG_OPT) -endif - -CFLAGS_COMMON = -v -mt -L$(OBJDIR) -xc99=%none -CFLAGS_COMMON += -xCC -CFLAGS_COMMON += -errshort=tags -CFLAGS_OPT = $(POPT) -CFLAGS_DBG = $(CFLAGS_DEBUG_OPTION) -CFLAGS_COMMON += -Xa $(CFLAGS_REQUIRED) - -# Assume MT behavior all the time (important) -CXXFLAGS_COMMON = -mt - -# Assume no C++ exceptions are used -CXXFLAGS_COMMON += -features=no%except -DCC_NOEX - -# For C++, these options tell it to assume nothing about locating libraries -# either at compile time, or at runtime. Use of these options will likely -# require the use of -L and -R options to indicate where libraries will -# be found at compile time (-L) and at runtime (-R). -# The /usr/lib location comes for free, so no need to specify that one. -# Note: C is much simplier and there is no need for these options. This -# is mostly needed to avoid dependencies on libraries in the -# Compiler install area, also see LIBCXX and LIBM. -CXXFLAGS_COMMON += -norunpath -xnolib - -# -# Treat compiler warnings as errors, if requested -# -ifeq ($(COMPILER_WARNINGS_FATAL),true) - CFLAGS_COMMON += -errwarn=%all - CXXFLAGS_COMMON += -errwarn=%all -endif - -CXXFLAGS_OPT = $(POPT) -CXXFLAGS_DBG = $(CXXFLAGS_DEBUG_OPTION) -CXXFLAGS_COMMON += $(CFLAGS_REQUIRED) - -# Add -xstrconst to the library compiles. This forces all string -# literals into the read-only data section, which prevents them from -# being written to and increases the runtime pages shared on the system. -# -ifdef LIBRARY - CFLAGS_COMMON +=-xstrconst -endif - -# Source browser database -# -# COMPILE_WITH_SB -# If defined adds -xsb to compiles and creates a -# source browsing database during compilation. -# -ifdef COMPILE_WITH_SB - ifeq ($(LIBRARY), java) - CFLAGS_DBG += -xsb - endif -endif - -# Lint Flags: -# -Xa ANSI C plus K&R, favor ANSI rules -# -Xarch=XXX Same as 'cc -xarch=XXX' -# -fd report on old style func defs -# -errchk=structarg report on 64bit struct args by value -# -errchk=longptr64 report on 64bit to 32bit issues (ignores casts) -# -errchk=parentheses report on suggested use of extra parens -# -v suppress unused args -# -x suppress unused externs -# -u suppress extern func/vars used/defined -# -errfmt=simple use one line errors with position info - -LINTFLAGS_COMMON = -Xa -LINTFLAGS_COMMON += -fd -LINTFLAGS_COMMON += -errchk=structarg,longptr64,parentheses -LINTFLAGS_COMMON += -v -LINTFLAGS_COMMON += -x -LINTFLAGS_COMMON += -u -LINTFLAGS_COMMON += -errfmt=simple -LINTFLAGS_OPT = -LINTFLAGS_DBG = - -# The -W0,-noglobal tells the compiler to NOT generate mangled global -# ELF data symbols for file local static data. -# This can break fix&continue, but we'd rather do the same compilations -# for deliverable bits as we do for non-deliverable bits -# Tell the compilers to never generate globalized names, all the time. -CFLAGS_COMMON += -W0,-noglobal - -# Arch specific settings (determines type of .o files and instruction set) -ifeq ($(ARCH_FAMILY), sparc) - ifdef VIS_NEEDED - XARCH_VALUE/32=v8plusa - XARCH_VALUE/64=v9a - else - # Someday this should change to improve optimization on UltraSPARC - # and abandon the old v8-only machines like the SPARCstation 10. - # Indications with Mustang is that alacrity runs do not show a - # big improvement using v8plus over v8, but other benchmarks might. - XARCH_VALUE/32=v8 - XARCH_VALUE/64=v9 - endif -endif -ifeq ($(ARCH_FAMILY), i586) - XARCH_VALUE/64=amd64 - XARCH_VALUE/32= -endif - -# Arch value based on current data model being built -XARCH_VALUE=$(XARCH_VALUE/$(ARCH_DATA_MODEL)) -ifneq ($(XARCH_VALUE), ) - # The actual compiler -xarch options to use - XARCH_OPTION/32 = -xarch=$(XARCH_VALUE/32) - XARCH_OPTION/64 = -xarch=$(XARCH_VALUE/64) - XARCH_OPTION = $(XARCH_OPTION/$(ARCH_DATA_MODEL)) -endif - -# If we have a specific -xarch value to use, add it -ifdef XARCH_OPTION - CFLAGS_COMMON += $(XARCH_OPTION) - CXXFLAGS_COMMON += $(XARCH_OPTION) - ASFLAGS_COMMON += $(XARCH_OPTION) - EXTRA_LIBS += $(XARCH_OPTION) - LINTFLAGS_COMMON += -Xarch=$(XARCH_VALUE) -endif - -# -# uncomment the following to build with PERTURBALOT set -# -# OTHER_CFLAGS += -DPERTURBALOT -# - -CPPFLAGS_COMMON = -D$(ARCH_FAMILY) -D__solaris__ -D_REENTRANT -CPPFLAGS_OPT = -CPPFLAGS_DBG = -DDEBUG - -ifeq ($(ARCH_FAMILY), i586) - # The macro _LITTLE_ENDIAN needs to be defined the same to avoid the - # Sun C compiler warning message: warning: macro redefined: _LITTLE_ENDIAN - # (The Solaris X86 system defines this in file /usr/include/sys/isa_defs.h). - # Note: -Dmacro is the same as #define macro 1 - # -Dmacro= is the same as #define macro - # - CPPFLAGS_COMMON += -DcpuIntel -D_LITTLE_ENDIAN= -D$(LIBARCH) - # Turn off a superfluous compiler error message on Intel - CFLAGS_COMMON += -erroff=E_BAD_PRAGMA_PACK_VALUE -endif - -# Java memory management is based on memory mapping by default, but a -# system only assuming malloc/free can be built by adding -DUSE_MALLOC - -CPPFLAGS_COMMON += -DTRACING -DMACRO_MEMSYS_OPS -DBREAKPTS -CPPFLAGS_OPT += -DTRIMMED - -LDFLAGS_DEFS_OPTION = -z defs -LDFLAGS_COMMON += $(LDFLAGS_DEFS_OPTION) - -# -# -L paths for finding and -ljava -# -LDFLAGS_COMMON += -L$(LIBDIR)/$(LIBARCH) -LDFLAGS_OPT = -LDFLAGS_DBG = - -# -# We never really want the incremental linker, ever -# The -xildoff option tells Sun's compilers to NOT use incremental linker -# -LDFLAGS_COMMON += -xildoff - -ifdef LIBRARY - # Libraries need to locate other libraries at runtime, and you can tell - # a library where to look by way of the dynamic runpaths (RPATH or RUNPATH) - # buried inside the .so. The $ORIGIN says to look relative to where - # the library itself is and it can be followed with relative paths from - # that. By default we always look in $ORIGIN, optionally we add relative - # paths if the Makefile sets LD_RUNPATH_EXTRAS to those relative paths. - # The environment variable LD_LIBRARY_PATH will over-ride these runpaths. - # Try: 'dump -Lv lib*.so' to see these settings in a library. - # - LDFLAGS_COMMON += -R\$$ORIGIN - LDFLAGS_COMMON += $(LD_RUNPATH_EXTRAS:%=-R\$$ORIGIN/%) -endif - -EXTRA_LIBS += -lc - -# Postprocessing is done on the images directories only -# -ifeq ($(VARIANT), OPT) - ifeq ($(PARTIAL_GPROF), true) - NO_STRIP = true - endif - ifeq ($(GPROF), true) - NO_STRIP = true - endif - ifneq ($(NO_STRIP), true) - # Debug 'strip -x' leaves local function Elf symbols (better stack traces) - POST_STRIP_PROCESS = $(STRIP) -x - endif -endif -POST_MCS_PROCESS=$(MCS) -d -a "JDK $(FULL_VERSION)" - -# -# Sun C compiler will take -M and pass it on to ld. -# Usage: ld $(LD_MAPFILE_FLAG) mapfile *.o -# -ifeq ($(CC_VERSION),gcc) -LD_MAPFILE_FLAG = -Xlinker -M -Xlinker -else -LD_MAPFILE_FLAG = -M -endif - -# -# Variables globally settable from the make command line (default -# values in brackets): -# GPROF (false) -# Eg: % gnumake GPROF=true -GPROF = false -ifeq ($(GPROF), true) - CFLAGS_COMMON += -DGPROF -xpg - EXTRA_LIBS += -xpg -endif - -# PARTIAL_GPROF is to be used ONLY during compilation - it should not -# appear during linking of libraries or programs. It also should -# prevent linking with -z defs to allow a symbol to remain undefined. -# -PARTIAL_GPROF = false -ifeq ($(PARTIAL_GPROF), true) - CFLAGS_GPROF += -xpg - LDFLAGS_DEFS_OPTION = -z nodefs -endif - -# -# For a TCOV build we add in the TCOV_OPTION -# -ifdef TCOV_BUILD - TCOV_OPTION = -xprofile=tcov - LDFLAGS_COMMON += $(TCOV_OPTION) -Kpic - CFLAGS_COMMON += $(TCOV_OPTION) - CXXFLAGS_COMMON += $(TCOV_OPTION) - EXTRA_LIBS += $(TCOV_OPTION) - LDNOMAP=true -endif - -# -# Solaris only uses native threads. -# -THREADS_FLAG= native -THREADS_DIR= threads - -# -# Support for Quantify. -# -ifdef QUANTIFY - QUANTIFY_CMD = quantify - QUANTIFY_OPTIONS = -cache-dir=/tmp/quantify -always-use-cache-dir=yes - LINK_PRE_CMD = $(QUANTIFY_CMD) $(QUANTIFY_OPTIONS) - ifdef LIBRARY - CFLAGS_COMMON += -K PIC - endif -endif - -# -# Support for Purify. -# -ifdef PURIFY - PURIFY_CMD = /net/suntools.eng/export/tools/sparc/bin/purify - PURIFY_OPTIONS = -cache-dir=/tmp/quantify -always-use-cache-dir=yes - LINK_PRE_CMD = $(PURIFY_CMD) $(PURIFY_OPTIONS) - ifdef LIBRARY - CFLAGS_COMMON += -K PIC - endif -endif - -# -# Different "levels" of optimization. -# -ifeq ($(CC_VERSION),gcc) - CC_HIGHEST_OPT = -O3 - CC_HIGHER_OPT = -O3 - CC_LOWER_OPT = -O2 - CFLAGS_REQUIRED_i586 += -fno-omit-frame-pointer - CFLAGS_REQUIRED_amd64 += -fno-omit-frame-pointer - # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) - # (See Rules.gmk) May need to wait for gcc 5? - AUTOMATIC_PCH_OPTION = -else - # Highest could be -xO5, but indications are that -xO5 should be reserved - # for a per-file use, on sources with known performance impacts. - CC_HIGHEST_OPT = -xO4 - CC_HIGHER_OPT = -xO4 - CC_LOWER_OPT = -xO2 - # - # WARNING: Use of _OPT=$(CC_HIGHEST_OPT) in your Makefile needs to be - # done with care, there are some assumptions below that need to - # be understood about the use of pointers, and IEEE behavior. - # - # Use non-standard floating point mode (not IEEE 754) - CC_HIGHEST_OPT += -fns - # Do some simplification of floating point arithmetic (not IEEE 754) - CC_HIGHEST_OPT += -fsimple - # Use single precision floating point with 'float' - CC_HIGHEST_OPT += -fsingle - # Assume memory references via basic pointer types do not alias - # (Source with excessing pointer casting and data access with mixed - # pointer types are not recommended) - CC_HIGHEST_OPT += -xalias_level=basic - # Use intrinsic or inline versions for math/std functions - # (If you expect perfect errno behavior, do not use this) - CC_HIGHEST_OPT += -xbuiltin=%all - # Loop data dependency optimizations (need -xO3 or higher) - CC_HIGHEST_OPT += -xdepend - # Pointer parameters to functions do not overlap - # (Similar to -xalias_level=basic usage, but less obvious sometimes. - # If you pass in multiple pointers to the same data, do not use this) - CC_HIGHEST_OPT += -xrestrict - # Inline some library routines - # (If you expect perfect errno behavior, do not use this) - CC_HIGHEST_OPT += -xlibmil - # Use optimized math routines - # (If you expect perfect errno behavior, do not use this) - # Can cause undefined external on Solaris 8 X86 on __sincos, removing for now - # CC_HIGHEST_OPT += -xlibmopt - ifeq ($(ARCH_FAMILY), sparc) - # Assume at most 8byte alignment, raise SIGBUS on error - ### Presents an ABI issue with customer JNI libs? - ####CC_HIGHEST_OPT += -xmemalign=8s - # Automatic prefetch instructions, explicit prefetch macros - CC_HIGHEST_OPT += -xprefetch=auto,explicit - # Pick ultra as the chip to optimize to - CC_HIGHEST_OPT += -xchip=ultra - endif - ifeq ($(ARCH), i586) - # Pick pentium as the chip to optimize to - CC_HIGHEST_OPT += -xchip=pentium - endif - ifdef LIBRARY - # The Solaris CBE (Common Build Environment) requires that the use - # of appl registers be disabled when compiling a public library (or - # a library that's loaded by a public library) on sparc. - CFLAGS_REQUIRED_sparc += -xregs=no%appl - CFLAGS_REQUIRED_sparcv9 += -xregs=no%appl - endif - ifeq ($(shell $(EXPR) $(CC_VER) \> 5.6), 1) - # Do NOT use the frame pointer register as a general purpose opt register - CFLAGS_REQUIRED_i586 += -xregs=no%frameptr - CFLAGS_REQUIRED_amd64 += -xregs=no%frameptr - # We MUST allow data alignment of 4 for sparc V8 (32bit) - # Presents an ABI issue with customer JNI libs? We must be able to - # to handle 4byte aligned objects? (rare occurance, but possible?) - CFLAGS_REQUIRED_sparc += -xmemalign=4s - endif - # Just incase someone trys to use the SOS9 compilers - ifeq ($(CC_VER), 5.6) - # We MUST allow data alignment of 4 for sparc (sparcv9 is ok at 8s) - CFLAGS_REQUIRED_sparc += -xmemalign=4s - endif - # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) - # (See Rules.gmk) The SS11 -xpch=auto* options appear to be broken. - AUTOMATIC_PCH_OPTION = -endif -CC_NO_OPT = - -# If NO_OPTIMIZATIONS is defined in the environment, turn all optimzations off -ifdef NO_OPTIMIZATIONS - CC_HIGHEST_OPT = $(CC_NO_OPT) - CC_HIGHER_OPT = $(CC_NO_OPT) - CC_LOWER_OPT = $(CC_NO_OPT) -endif - -# Flags required all the time -CFLAGS_REQUIRED = $(CFLAGS_REQUIRED_$(ARCH)) - -# Add processor specific options for optimizations -CC_HIGHEST_OPT += $(_OPT_$(ARCH)) -CC_HIGHER_OPT += $(_OPT_$(ARCH)) -CC_LOWER_OPT += $(_OPT_$(ARCH)) - -# Secret compiler optimization options that should be in the above macros -# but since they differ in format from C to C++, are added into the C or -# C++ specific macros for compiler flags. -# -# On i586 we need to tell the code generator to ALWAYS use a -# frame pointer. -ifeq ($(ARCH_FAMILY), i586) - # Note that in 5.7, this is done with -xregs=no%frameptr - ifeq ($(CC_VER), 5.5) - # It's not exactly clear when this optimization kicks in, the - # current assumption is -xO4 or greater and for C++ with - # the -features=no%except option and -xO4 and greater. - # Bottom line is, we ALWAYS want a frame pointer! - CXXFLAGS_OPT += -Qoption ube -Z~B - CFLAGS_OPT += -Wu,-Z~B - ifeq ($(FASTDEBUG), true) - CXXFLAGS_DBG += -Qoption ube -Z~B - CFLAGS_DBG += -Wu,-Z~B - endif - endif -endif -# -# Optimizer for sparc needs to be told not to do certain things -# related to frames or save instructions. -ifeq ($(ARCH_FAMILY), sparc) - # NOTE: Someday the compilers will provide a high-level option for this. - # Use save instructions instead of add instructions - # This was an optimization starting in SC5.0 that made it hard for us to - # find the "save" instruction (which got turned into an "add") - CXXFLAGS_OPT += -Qoption cg -Qrm-s - CFLAGS_OPT += -Wc,-Qrm-s - ifeq ($(FASTDEBUG), true) - CXXFLAGS_DBG += -Qoption cg -Qrm-s - CFLAGS_DBG += -Wc,-Qrm-s - endif - # - # NOTE: Someday the compilers will provide a high-level option for this. - # Don't allow tail call code optimization. Started in SC5.0. - # We don't like code of this form: - # save - # - # call foo - # restore - # because we can't tell if the method will have a stack frame - # and register windows or not. - CXXFLAGS_OPT += -Qoption cg -Qiselect-T0 - CFLAGS_OPT += -Wc,-Qiselect-T0 - ifeq ($(FASTDEBUG), true) - CXXFLAGS_DBG += -Qoption cg -Qiselect-T0 - CFLAGS_DBG += -Wc,-Qiselect-T0 - endif -endif - -# -# Path and option to link against the VM, if you have to. Note that -# there are libraries that link against only -ljava, but they do get -# -L to the -ljvm, this is because -ljava depends on -ljvm, whereas -# the library itself should not. -# -VM_NAME = server -JVMLIB = -L$(BOOTDIR)/jre/lib/$(LIBARCH)/server -ljvm -JAVALIB = - -# Part of INCREMENTAL_BUILD mechanism. -# Compiler emits things like: path/file.o: file.h -# We want something like: relative_path/file.o relative_path/file.d: file.h -# In addition on Solaris, any include file starting with / is deleted, -# this gets rid of things like /usr/include files, which never change. -CC_DEPEND = -xM1 -CC_DEPEND_FILTER = $(SED) -e '/:[ ]*[/]/d' -e 's!$*\.$(OBJECT_SUFFIX)!$(dir $@)& $(dir $@)$*.$(DEPEND_SUFFIX)!g' | $(SORT) -u - -# Location of openwin libraries (do we really need this anymore?) -OPENWIN_HOME = /usr/openwin -OPENWIN_LIB = $(OPENWIN_HOME)/lib$(ISA_DIR) - -# Runtime graphics library search paths... -OPENWIN_RUNTIME_LIB = /usr/openwin/lib$(ISA_DIR) -AWT_RUNPATH = -R/usr/dt/lib$(ISA_DIR) -R$(OPENWIN_RUNTIME_LIB) - -# C++ Runtime library (libCrun.so), use instead of -lCrun. -# Originally used instead of -lCrun to guarantee use of the system -# .so version and not the .a or .so that came with the compilers. -# With the newer compilers this could probably change back to -lCrun but -# in general this is ok to continue to do. -LIBCXX = /usr/lib$(ISA_DIR)/libCrun.so.1 - -# Math Library (libm.so), do not use -lm. -# There might be two versions of libm.so on the build system: -# libm.so.1 and libm.so.2, and we want libm.so.1. -# Depending on the Solaris release being used to build with, -# /usr/lib/libm.so could point at a libm.so.2, so we are -# explicit here so that the libjvm.so you have built will work on an -# older Solaris release that might not have libm.so.2. -# This is a critical factor in allowing builds on Solaris 10 or newer -# to run on Solaris 8 or 9. -# -# Note: Historically there was also a problem picking up a static version -# of libm.a from the compiler area, but that problem has gone away -# with the newer compilers. Use of libm.a would cause .so bloat. -# -LIBM = /usr/lib$(ISA_DIR)/libm.so.1 - -# Socket library -LIBSOCKET = -lsocket - -# GLOBAL_KPIC: If set means all libraries are PIC, position independent code -# EXCEPT for select compiles -# If a .o file is compiled non-PIC then it should be forced -# into the RW data segment with a mapfile option. This is done -# with object files which generated from .s files. -# The -ztext enforces that no relocations remain in the text segment -# so that it remains purely read-only for optimum system performance. -# Some libraries may use a smaller size (13bit -Kpic) on sparc instead of -# (32 bit -KPIC) and will override GLOBAL_KPIC appropriately. -# -PIC_CODE_LARGE = -KPIC -PIC_CODE_SMALL = -Kpic -ifndef TCOV_BUILD - GLOBAL_KPIC = $(PIC_CODE_LARGE) - CXXFLAGS_COMMON += $(GLOBAL_KPIC) - CFLAGS_COMMON += $(GLOBAL_KPIC) - LDFLAGS_COMMON += -ztext -endif # TCOV_BUILD - -# If your platform has DPS, it will have Type1 fonts too, in which case -# it is best to enable DPS support until such time as 2D's rasteriser -# can fully handle Type1 fonts in all cases. Default is "yes". -# HAVE_DPS should only be "no" if the platform has no DPS headers or libs -# DPS (Displayable PostScript) is available on Solaris machines - -HAVE_DPS = yes - -# -# Japanese manpages -# -JA_SOURCE_ENCODING = eucJP -JA_TARGET_ENCODINGS = eucJP UTF-8 PCK - diff --git a/corba/make/common/Defs-windows.gmk b/corba/make/common/Defs-windows.gmk index 7dc24d975da..cef6c6c60b8 100644 --- a/corba/make/common/Defs-windows.gmk +++ b/corba/make/common/Defs-windows.gmk @@ -31,363 +31,7 @@ # Get shared JDK settings include $(BUILDDIR)/common/shared/Defs.gmk -# CC compiler object code output directive flag value -CC_OBJECT_OUTPUT_FLAG = -Fo -CC_PROGRAM_OUTPUT_FLAG = -Fe - -# The suffix applied to the library name for FDLIBM -FDDLIBM_SUFFIX = lib -# The suffix applied to scripts (.bat for windows, nothing for unix) -SCRIPT_SUFFIX = .bat - -HPIS = windows -# LIB_LOCATION, which for windows identifies where .exe files go, may be -# set by each GNUmakefile. The default is BINDIR. -ifndef LIB_LOCATION - LIB_LOCATION = $(BINDIR) -endif # LIB_LOCATION - ifndef PLATFORM_SRC PLATFORM_SRC = $(TOPDIR)/src/windows endif # PLATFORM_SRC -# for backwards compatability, the old "win32" is used here instead of -# the more proper "windows" -PLATFORM_INCLUDE_NAME = win32 -PLATFORM_INCLUDE = $(INCLUDEDIR)/$(PLATFORM_INCLUDE_NAME) - -# The following DLL's are considered MS runtime libraries and should -# not to be REBASEd, see deploy/make/common/Release.gmk. -# msvcrt.dll, msvcrnn.dll [msvcr71 or msvcr80 or msvcr90] : Microsoft runtimes -MS_RUNTIME_LIBRARIES = msvcrt.dll -MSVCRNN_DLL = -ifeq ($(ARCH_DATA_MODEL), 32) - ifeq ($(COMPILER_VERSION), VS2003) - MSVCRNN_DLL = msvcr71.dll - MSVCPNN_DLL = msvcp71.dll - MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) - endif - ifeq ($(COMPILER_VERSION), VS2005) - MSVCRNN_DLL = msvcr80.dll - MSVCPNN_DLL = msvcp80.dll - MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) - endif - ifeq ($(COMPILER_VERSION), VS2008) - MSVCRNN_DLL = msvcr90.dll - MSVCPNN_DLL = msvcp90.dll - MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) - endif - ifeq ($(COMPILER_VERSION), VS2010) - MSVCRNN_DLL = msvcr100.dll - MSVCPNN_DLL = msvcp100.dll - MS_RUNTIME_LIBRARIES += $(MSVCRNN_DLL) - endif -endif - -# C Compiler flag definitions - -# -# Default optimization -# -ifeq ($(CC_VERSION),msvc) - # Visual Studio .NET 2003 or VS2003 compiler option definitions: - # -O1 Favors reduced size over speed (-Og -Os -Oy -Ob2 -Gs -GF -Gy) - # -O2 Favors speed over reduced size (-Og -Oi -Ot -Oy -Ob2 -Gs -GF -Gy) - # -Ox Full optimization (use -O2) (-Og -Oi -Ot -Oy -Ob2) - # (Removed in Visual Studio 2005 or VS2005) - # -Ob2 More aggressive inlining - # -Og Global optimizations - # -Oi Replace some functions with intrinsic or special forms - # -Op Improve floating point calculations (disables some optimizations) - # (Replaced with -fp:precise in VS2005, /Op is default now) - # -Os Favor small code - # -Ot Favor faster code - # -Oy Frame pointer omission - # -GB Optimize for pentium (old VC6 option?) - # -G6 VS2003 version of -GB? - # -GF Pool strings in read-only memory - # -Gf Pool strings in read-write memory (the default) - # -Gs Controls stack probess - # -GS Adds buffer overflow checks on stacks - # (Default in VS2005) - # -GX Enables exception handling - # (Replaced with /EHsc in VS2005) - # -Gy Function level linking only - # - # NOTE: With VC6, -Ox included -Gs. - # NOTE: With VC6, -Ox, -O1, and -O2 used -Ob1, not -Ob2. - # NOTE: With VC6, -O1 and -O2 used -Gf, not -GF. - # - ifeq ($(COMPILER_VERSION), VC6) - # VC6 (6.2) msvc compiler (the way Tiger and early Mustang were built) - # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) - AUTOMATIC_PCH_OPTION = - GX_OPTION = -GX - ifeq ($(ARCH_DATA_MODEL), 32) - CC_HIGHEST_OPT = -Ox -Gy -Os -GB - CC_HIGHER_OPT = -Ox -Gy -Os -GB - CC_LOWER_OPT = -Ox -Gy -Os -GB - else - CC_HIGHEST_OPT = -Ox -Gy -Op - CC_HIGHER_OPT = -Ox -Gy -Op - CC_LOWER_OPT = -Ox -Gy -Op - endif - endif - ifeq ($(COMPILER_VERSION), VS2003) - # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) - AUTOMATIC_PCH_OPTION = -YX - # Also known as VC7 compiler - GX_OPTION = -GX - ifeq ($(ARCH_DATA_MODEL), 32) - # Lowered opt level to try and reduce footprint, dll size especially. - # Was: CC_HIGHEST_OPT = -O2 -G6 - # Was: CC_HIGHER_OPT = -O2 - CC_HIGHEST_OPT = -O2 - CC_HIGHER_OPT = -O1 - CC_LOWER_OPT = -O1 - else - CC_HIGHEST_OPT = -O2 -Op - CC_HIGHER_OPT = -O2 -Op - CC_LOWER_OPT = -O1 -Op - endif - endif - ifeq ($(COMPILER_VERSION), VS2005) - # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) - AUTOMATIC_PCH_OPTION = - # VS2005 compiler, only with Platform SDK right now? - GX_OPTION = -EHsc - ifeq ($(ARCH_DATA_MODEL), 32) - CC_HIGHEST_OPT = -O2 - CC_HIGHER_OPT = -O1 - CC_LOWER_OPT = -O1 - else - CC_HIGHEST_OPT = -O2 - CC_HIGHER_OPT = -O1 - CC_LOWER_OPT = -O1 - endif - endif - ifeq ($(COMPILER_VERSION), VS2008) - # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) - AUTOMATIC_PCH_OPTION = - GX_OPTION = -EHsc - ifeq ($(ARCH_DATA_MODEL), 32) - CC_HIGHEST_OPT = -O2 - CC_HIGHER_OPT = -O1 - CC_LOWER_OPT = -O1 - else - CC_HIGHEST_OPT = -O2 - CC_HIGHER_OPT = -O1 - CC_LOWER_OPT = -O1 - endif - endif - ifeq ($(COMPILER_VERSION), VS2010) - # Automatic precompiled header option to use (if COMPILE_APPROACH=batch) - AUTOMATIC_PCH_OPTION = - GX_OPTION = -EHsc - ifeq ($(ARCH_DATA_MODEL), 32) - CC_HIGHEST_OPT = -O2 - CC_HIGHER_OPT = -O1 - CC_LOWER_OPT = -O1 - else - CC_HIGHEST_OPT = -O2 - CC_HIGHER_OPT = -O1 - CC_LOWER_OPT = -O1 - endif - endif - CC_NO_OPT = -Od -else # CC_VERSION - # GCC not supported, but left for historical reference... - CC_HIGHEST_OPT = -O3 - CC_HIGHER_OPT = -O2 - CC_LOWER_OPT = -O2 - CC_NO_OPT = -endif - -# If NO_OPTIMIZATIONS is defined in the environment, turn all optimzations off -ifdef NO_OPTIMIZATIONS - CC_HIGHEST_OPT = $(CC_NO_OPT) - CC_HIGHER_OPT = $(CC_NO_OPT) - CC_LOWER_OPT = $(CC_NO_OPT) -endif - -ifeq ($(PRODUCT), java) - _OPT = $(CC_HIGHER_OPT) -else - _OPT = $(CC_LOWER_OPT) -endif - -# Select the runtime support library carefully, need to be consistent -# -# VS2003 compiler option definitions: -# -MD Use dynamic multi-threaded runtime library -# -MDd Use debug version (don't use, doesn't mix with -MD DLL's) -# -MT Use static multi-threaded runtime library (-ML is going away) -# -MTd Use static debug version (better than -MDd, no runtime issues) -# -D_DEBUG Change use of malloc/free/etc to use special debug ones (-MTd) -# -# NOTE: We also will use /D _STATIC_CPPLIB so we don't need msvcpnn.dll -# -ifeq ($(MS_RUNTIME_STATIC),true) - MS_RUNTIME_OPTION=-MT -else - MS_RUNTIME_OPTION=-MD -endif -# The _DEBUG macro option (changes things like malloc to use debug version) -MS_RUNTIME_DEBUG_OPTION= -MS_RC_DEBUG_OPTION= -# Externally set environment variable can force any build to use the debug vers -ifeq ($(MFC_DEBUG), true) - ifeq ($(MS_RUNTIME_STATIC),true) - MS_RUNTIME_OPTION=-MTd - else - # This MS debugging flag forces a dependence on the debug - # version of the runtime library (MSVCRTD.DLL), as does -MDd. - # We cannot re-distribute this debug runtime. - MS_RUNTIME_OPTION=-MDd - endif - MS_RUNTIME_DEBUG_OPTION= -D_DEBUG - MS_RC_DEBUG_OPTION= -d _DEBUG -endif - -# Always add _STATIC_CPPLIB definition -STATIC_CPPLIB_OPTION = /D _STATIC_CPPLIB -MS_RUNTIME_OPTION += $(STATIC_CPPLIB_OPTION) - -ifeq ($(CC_VERSION),msvc) - # VS2003 compiler option definitions: - # -Zi Cause *.pdb file to be created, full debug information - # -Z7 Full debug inside the .obj, no .pdb - # -Zd Basic debug, no local variables? In the .obj - # -Zl Don't add runtime library name to obj file? - # -Od Turns off optimization and speeds compilation - # -YX -Fp/.../foobar.pch Use precompiled headers (try someday?) - # -nologo Don't print out startup message - # /D _STATIC_CPPLIB - # Use static link for the C++ runtime (so msvcpnn.dll not needed) - # - CFLAGS_COMMON += -Zi -nologo - CFLAGS_OPT = $(POPT) - CFLAGS_DBG = -Od $(MS_RUNTIME_DEBUG_OPTION) - - # Starting from VS2005 the wchar_t is handled as a built-in C/C++ data type - # by default. However, we expect the wchar_t to be a typedef to the - # unsigned short data type. The -Zc:wchar_t- option restores the old - # behavior (as seen in VS2003) to avoid massive code modifications. - # When/if our code will be "C/C++ Standard"-compliant (at least in the area - # of handling the wchar_t type), the option won't be necessary. - ifeq ($(ARCH_DATA_MODEL), 32) - CFLAGS_VS2005 += -Zc:wchar_t- - else - # The 64bit Platform SDK we use (April 2005) doesn't like this option - ifneq ($(CC_VER), 14.00.40310.41) - CFLAGS_VS2005 += -Zc:wchar_t- - endif - endif - - # All builds get the same runtime setting - CFLAGS_COMMON += $(MS_RUNTIME_OPTION) $(CFLAGS_$(COMPILER_VERSION)) - - - LDEBUG = /debug - - ifeq ($(VTUNE_SUPPORT), true) - OTHER_CFLAGS = -Z7 -Ox - LDEBUG += /pdb:NONE - endif - - # The new Platform SDK and VS2005 has /GS as a default and requires - # bufferoverflowU.lib on the link command line, otherwise - # we get missing __security_check_cookie externals at link time. - BUFFEROVERFLOWLIB = bufferoverflowU.lib - # Always add bufferoverflowU.lib to VS2005 link commands (pack uses LDDFLAGS) - LFLAGS_VS2005 = $(BUFFEROVERFLOWLIB) - - # LFLAGS are the flags given to $(LINK) and used to build the actual DLL file - BASELFLAGS = -nologo /opt:REF /incremental:no - LFLAGS = $(BASELFLAGS) $(LDEBUG) $(EXTRA_LFLAGS) $(LFLAGS_$(COMPILER_VERSION)) - LDDFLAGS += $(LFLAGS_$(COMPILER_VERSION)) - -endif - -# -# Preprocessor macro definitions -# -CPPFLAGS_COMMON = -DWIN32 -DIAL -D_LITTLE_ENDIAN -ifeq ($(ARCH), amd64) - CPPFLAGS_COMMON += -D_AMD64_ -Damd64 -else - CPPFLAGS_COMMON += -DWIN32 -D_X86_ -Dx86 -endif -CPPFLAGS_COMMON += -DWIN32_LEAN_AND_MEAN - -# -# Output options (use specific filenames to avoid parallel compile errors) -# -CFLAGS_COMMON += -Fd$(OBJDIR)/$(basename $(@F)).pdb -Fm$(OBJDIR)/$(basename $(@F)).map - -# -# Add warnings and extra on 64bit issues -# -ifeq ($(ARCH_DATA_MODEL), 64) - CFLAGS_COMMON += -Wp64 -endif -CFLAGS_COMMON += -W$(COMPILER_WARNING_LEVEL) - -# -# Treat compiler warnings as errors, if requested -# -ifeq ($(COMPILER_WARNINGS_FATAL),true) - CFLAGS_COMMON += -WX -endif - -CPPFLAGS_OPT = -CPPFLAGS_DBG = -DDEBUG -DLOGGING - -CXXFLAGS_COMMON = $(CFLAGS_COMMON) -CXXFLAGS_OPT = $(CFLAGS_OPT) -CXXFLAGS_DBG = $(CFLAGS_DBG) - -ifneq ($(LIBRARY),fdlibm) - EXTRA_LIBS += advapi32.lib -endif - -# -# Path and option to link against the VM, if you have to. -# -JVMLIB = $(BOOTDIR)/lib/jvm.lib -JAVALIB = - -ifeq ($(CC_VERSION), msvc) - CC_DEPEND = -FD - CC_DEPEND_FILTER = -else # CC_VERSION -# not supported, but left for historical reference... - CC_DEPEND = -MM - CC_DEPEND_FILTER = $(SED) -e 's!$*\.$(OBJECT_SUFFIX)!$(dir $@)&!g' -endif # CC_VERSION - -LIBRARY_SUFFIX = dll -LIB_SUFFIX = lib - -# Settings for the VERSIONINFO tap on windows. -VERSIONINFO_RESOURCE = $(TOPDIR)/src/windows/resource/version.rc - -RC_FLAGS = /l 0x409 /r - -ifeq ($(VARIANT), OPT) - RC_FLAGS += -d NDEBUG -else - RC_FLAGS += $(MS_RC_DEBUG_OPTION) -endif - -ifndef COPYRIGHT_YEAR - COPYRIGHT_YEAR = 2007 -endif - -RC_FLAGS += -d "JDK_BUILD_ID=$(FULL_VERSION)" \ - -d "JDK_COMPANY=$(COMPANY_NAME)" \ - -d "JDK_COMPONENT=$(PRODUCT_NAME) Platform SE binary" \ - -d "JDK_VER=$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION).$(JDK_UPDATE_VER).$(COOKED_BUILD_NUMBER)" \ - -d "JDK_COPYRIGHT=Copyright \xA9 $(COPYRIGHT_YEAR)" \ - -d "JDK_NAME=$(PRODUCT_NAME) Platform SE $(JDK_MINOR_VERSION) $(JDK_UPDATE_META_TAG)" \ - -d "JDK_FVER=$(JDK_VERSION)" diff --git a/corba/make/common/Defs.gmk b/corba/make/common/Defs.gmk index 2c2d03c48ce..2d5c83db6e0 100644 --- a/corba/make/common/Defs.gmk +++ b/corba/make/common/Defs.gmk @@ -73,54 +73,10 @@ JDK_LOCALES = ja zh_CN # JRE_NONEXIST_LOCALES = en en_US de_DE es_ES fr_FR it_IT ja_JP ko_KR sv_SE zh -# -# All libraries except libjava and libjvm itself link against libjvm and -# libjava, the latter for its exported common utilities. libjava only links -# against libjvm. Programs' makefiles take their own responsibility for -# adding other libs. -# -ifdef PACKAGE -# put JAVALIB first, but do not lose any platform specific values.... - LDLIBS_COMMON = $(JAVALIB) -endif # PACKAGE - -# -# Libraries that must appear ahead of libc.so on the link command line -# -ifdef PROGRAM - - ifeq ($(PLATFORM), solaris) - LDLIBS_COMMON = -lthread -ldl - endif - - ifeq ($(PLATFORM), linux) - LDLIBS_COMMON = -ldl - endif - -endif # PROGRAM - -LDLIBS_COMMON += $(EXTRA_LIBS) - -# -# Default is to build, not import native binaries -# -ifndef IMPORT_NATIVE_BINARIES - IMPORT_NATIVE_BINARIES=false -endif -# If importing libraries in, no incremental builds -ifeq ($(IMPORT_NATIVE_BINARIES),true) - INCREMENTAL_BUILD=false -endif - -# for generated libraries LIBDIR = $(OUTPUTDIR)/lib ABS_LIBDIR = $(ABS_OUTPUTDIR)/lib -# Optional place to save the windows .lib files -LIBFILES_DIR = $(OUTPUTDIR)/libfiles # for ext jre files EXTDIR = $(LIBDIR)/ext -# for generated include files -INCLUDEDIR = $(OUTPUTDIR)/include # for generated class files CLASSBINDIR = $(OUTPUTDIR)/classes DEMOCLASSDIR = $(OUTPUTDIR)/democlasses @@ -131,8 +87,6 @@ BUILDTOOLJARDIR = $(OUTPUTDIR)/btjars ABS_BUILDTOOLJARDIR = $(ABS_OUTPUTDIR)/btjars # for generated java source files GENSRCDIR = $(OUTPUTDIR)/gensrc -# for generated C source files (not javah) -GENNATIVESRCDIR = $(OUTPUTDIR)/gennativesrc # for imported source files IMPORTSRCDIR = $(OUTPUTDIR)/impsrc # for imported documents @@ -196,19 +150,6 @@ override ABS_TEMPDIR = $(ABS_OUTPUTDIR)/$(UNIQUE_PATH) dummy1:=$(shell $(MKDIR) -p $(TEMPDIR)) dummy2:=$(shell $(MKDIR) -p $(TEMP_DISK)) -# OBJDIRNAME is the name of the directory where the object code is to -# be placed. It's name depends on whether the data model architecture -# is 32-bit or not. -ifneq ($(ARCH_DATA_MODEL), 32) - OBJDIRNAME = obj$(ARCH_DATA_MODEL)$(OBJDIRNAME_SUFFIX) -else - OBJDIRNAME = obj$(OBJDIRNAME_SUFFIX) -endif -OBJDIR = $(TEMPDIR)/$(OBJDIRNAME) - -# CLASSHDRDIR is where the generated C Class Header files go. -CLASSHDRDIR = $(TEMPDIR)/CClassHeaders - # # CLASSDESTDIR can be used to specify the directory where generated classes # are to be placed. The default is CLASSBINDIR. @@ -217,11 +158,6 @@ ifndef CLASSDESTDIR CLASSDESTDIR = $(CLASSBINDIR) endif -INCLUDES = -I. -I$(CLASSHDRDIR) \ - $(patsubst %,-I%,$(subst $(CLASSPATH_SEPARATOR), ,$(VPATH.h))) $(OTHER_INCLUDES) -OTHER_CPPFLAGS = $(INCLUDES) - - # # vpaths. These are the default locations searched for source files. # GNUmakefiles of individual areas often override the default settings. @@ -235,35 +171,6 @@ VPATH0.java = $(GENSRCDIR)$(CLASSPATH_SEPARATOR)$(PLATFORM_SRC)/classes$(CLASSPA VPATH.java = $(VPATH0.java) vpath %.java $(VPATH.java) vpath %.class $(CLASSBINDIR) -vpath %.$(OBJECT_SUFFIX) $(OBJDIR) - -# -# VPATH.h is used elsewhere to generate include flags. By default, -# anyone has access to the include files that the JVM area exports, -# namely jni.h, jvm.h, and jni_utils.h, plus their platform-specific -# relatives. -# -ifeq ($(PLATFORM), windows) - VPATH.h = $(BOOTDIR)/include;$(BOOTDIR)/include/$(PLATFORM_INCLUDE_NAME) -else - VPATH.h = $(PLATFORM_SRC)/javavm/export$(CLASSPATH_SEPARATOR)$(SHARE_SRC)/javavm/export$(CLASSPATH_SEPARATOR)$(SHARE_SRC)/javavm/include$(CLASSPATH_SEPARATOR)$(PLATFORM_SRC)/javavm/include -endif -vpath %.h $(VPATH.h) - -# -# Used in two ways: helps link against libjava.so. Also if overridden -# determines where your shared library is installed. -# -ifndef LIB_LOCATION - LIB_LOCATION = $(LIBDIR)/$(LIBARCH) -endif - -# -# Java header and stub variables -# -CLASSHDRS = $(patsubst %,$(CLASSHDRDIR)/%.h,$(subst .,_,$(CLASSES.export))) -CLASSSTUBOBJS = classstubs.$(OBJECT_SUFFIX) -STUBPREAMBLE = $(INCLUDEDIR)/StubPreamble.h # # Classpath seen by javac (different from the one seen by the VM @@ -338,38 +245,9 @@ define OTHERSUBDIRS-loop done endef -# -# Create BYFILE OPT and DBG settings, if CFLAGS_OPT/foobar.o is set then it is -# used for this file, otherwise the default settings are used. -# -CFLAGS_$(VARIANT)/BYFILE = $(CFLAGS_$(VARIANT)/$(@F)) \ - $(CFLAGS_$(VARIANT)$(CFLAGS_$(VARIANT)/$(@F))) -CXXFLAGS_$(VARIANT)/BYFILE = $(CXXFLAGS_$(VARIANT)/$(@F)) \ - $(CXXFLAGS_$(VARIANT)$(CXXFLAGS_$(VARIANT)/$(@F))) - -# -# Tool flags -# -ASFLAGS = $(ASFLAGS_$(VARIANT)) $(ASFLAGS_COMMON) $(OTHER_ASFLAGS) -CFLAGS = $(CFLAGS_$(VARIANT)/BYFILE) $(CFLAGS_COMMON) $(OTHER_CFLAGS) -CXXFLAGS = $(CXXFLAGS_$(VARIANT)/BYFILE) $(CXXFLAGS_COMMON) $(OTHER_CXXFLAGS) -CPPFLAGS = $(CPPFLAGS_$(VARIANT)) $(CPPFLAGS_COMMON) $(OTHER_CPPFLAGS) \ - $(DEFINES) $(OPTIONS:%=-D%) -LDFLAGS = $(LDFLAGS_$(VARIANT)) $(LDFLAGS_COMMON) $(OTHER_LDFLAGS) -LDLIBS = $(OTHER_LDLIBS) $(LDLIBS_$(VARIANT)) $(LDLIBS_COMMON) -LINTFLAGS = $(LINTFLAGS_$(VARIANT)) $(LINTFLAGS_COMMON) \ - $(OTHER_LINTFLAGS) - -# this should be moved into Defs-.gmk..... -ifeq ($(PLATFORM), windows) - VERSION_DEFINES = -DRELEASE="\"$(RELEASE)\"" -else - VERSION_DEFINES = -DRELEASE='"$(RELEASE)"' -endif - # Prevent the use of many default suffix rules we do not need .SUFFIXES: -.SUFFIXES: .c .o .h .obj .cpp .hpp .java .class +.SUFFIXES: .java .class # Make sure we are all insane ifdef INSANE diff --git a/corba/make/common/Library.gmk b/corba/make/common/Library.gmk deleted file mode 100644 index ffd3a3ab701..00000000000 --- a/corba/make/common/Library.gmk +++ /dev/null @@ -1,275 +0,0 @@ -# -# Copyright (c) 1995, 2009, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# -# Generic makefile for building shared libraries. -# - -include $(TOPDIR)/make/common/Classes.gmk - -# -# It is important to define these *after* including Classes.gmk -# in order to override the values defined inthat makefile. -# - -ACTUAL_LIBRARY_NAME = $(LIB_PREFIX)$(LIBRARY).$(LIBRARY_SUFFIX) -ACTUAL_LIBRARY_DIR = $(LIB_LOCATION) -ACTUAL_LIBRARY = $(ACTUAL_LIBRARY_DIR)/$(ACTUAL_LIBRARY_NAME) - -library:: $(ACTUAL_LIBRARY) - -FILES_o = $(patsubst %.c, %.$(OBJECT_SUFFIX), $(addprefix $(OBJDIR)/, $(notdir $(FILES_c)))) -FILES_o += $(patsubst %.s, %.$(OBJECT_SUFFIX), $(addprefix $(OBJDIR)/, $(notdir $(FILES_s)))) -FILES_o += $(patsubst %.cpp, %.$(OBJECT_SUFFIX), $(addprefix $(OBJDIR)/, $(notdir $(FILES_cpp)))) - -ifeq ($(INCREMENTAL_BUILD),true) -FILES_d = $(patsubst %.c, %.$(DEPEND_SUFFIX), $(addprefix $(OBJDIR)/, $(notdir $(FILES_c)))) -FILES_d += $(patsubst %.cpp, %.$(DEPEND_SUFFIX), $(addprefix $(OBJDIR)/, $(notdir $(FILES_cpp)))) -endif # INCREMENTAL_BUILD - -ifeq ($(PLATFORM),solaris) -# List of all lint files, one for each .c file (only for C) -FILES_ln = $(patsubst %.c, %.$(LINT_SUFFIX), $(addprefix $(OBJDIR)/, $(notdir $(FILES_c)))) -endif - -# -# C++ libraries must be linked with CC. -# -ifdef CPLUSPLUSLIBRARY -LINKER=$(LINK.cc) -else -LINKER=$(LINK.c) -endif - -# We either need to import (copy) libraries in, or build them -$(ACTUAL_LIBRARY):: $(INIT) $(TEMPDIR) $(LIBDIR) $(BINDIR) $(EXTDIR) classheaders - -# -# COMPILE_APPROACH: Different approaches to compile up the native object -# files as quickly as possible. -# The setting of parallel works best on Unix, batch on Windows. -# - -COMPILE_FILES_o = $(OBJDIR)/.files_compiled -$(COMPILE_FILES_o): $(FILES_d) $(FILES_o) - @$(ECHO) "$<" >> $@ -clean:: - $(RM) $(COMPILE_FILES_o) - -# -# COMPILE_APPROACH=parallel: Will trigger compilations (just compilations) to -# happen in parallel. Greatly decreases Unix build time, even on single CPU -# machines, more so on multiple CPU machines. Default is 2 compiles -# at a time, but can be adjusted with ALT_PARALLEL_COMPILE_JOBS. -# Note that each .d file will also be dependent on it's .o file, see -# Rules.gmk. -# Note this does not depend on Rules.gmk to work like batch (below) -# and this technique doesn't seem to help Windows build time nor does -# it work very well, it's possible the Windows Visual Studio compilers -# don't work well in a parallel situation, this needs investigation. -# - -ifeq ($(COMPILE_APPROACH),parallel) - -.PHONY: library_parallel_compile - -library_parallel_compile: - @$(ECHO) "Begin parallel compiles: $(shell $(PWD))" - @$(MAKE) -j $(PARALLEL_COMPILE_JOBS) $(COMPILE_FILES_o) - @$(ECHO) "Done with parallel compiles: $(shell $(PWD))" - -$(ACTUAL_LIBRARY):: library_parallel_compile - -endif - -# -# COMPILE_APPROACH=batch: Will trigger compilations (just compilations) to -# happen in batch mode. Greatly decreases Windows build time. -# See logic in Rules.gmk for how compiles happen, the $(MAKE) in -# library_batch_compile below triggers the actions in Rules.gmk. -# Note that each .d file will also be dependent on it's .o file, see -# Rules.gmk. -# -ifeq ($(COMPILE_APPROACH),batch) - -.PHONY: library_batch_compile - -library_batch_compile: - @$(ECHO) "Begin BATCH compiles: $(shell $(PWD))" - $(MAKE) $(COMPILE_FILES_o) - $(MAKE) batch_compile - @$(ECHO) "Done with BATCH compiles: $(shell $(PWD))" - $(MAKE) COMPILE_APPROACH=normal $(COMPILE_FILES_o) - -$(ACTUAL_LIBRARY):: library_batch_compile - -endif - -ifeq ($(PLATFORM), windows) - -# -# Library building rules. -# - -$(LIBRARY).lib:: $(OBJDIR) - -# build it into $(OBJDIR) so that the other generated files get put -# there, then copy just the DLL (and MAP file) to the requested directory. -# -$(ACTUAL_LIBRARY):: $(OBJDIR)/$(LIBRARY).lcf - @$(prep-target) - @$(MKDIR) -p $(OBJDIR) - $(LINK) -dll -out:$(OBJDIR)/$(@F) \ - -map:$(OBJDIR)/$(LIBRARY).map \ - $(LFLAGS) @$(OBJDIR)/$(LIBRARY).lcf \ - $(OTHER_LCF) $(JAVALIB) $(LDLIBS) - $(CP) $(OBJDIR)/$(@F) $@ - $(CP) $(OBJDIR)/$(LIBRARY).map $(@D) - $(CP) $(OBJDIR)/$(LIBRARY).pdb $(@D) - -$(OBJDIR)/$(LIBRARY).lcf: $(OBJDIR)/$(LIBRARY).res $(COMPILE_FILES_o) $(FILES_m) - @$(prep-target) - @$(MKDIR) -p $(TEMPDIR) - @$(ECHO) $(FILES_o) > $@ -ifndef LOCAL_RESOURCE_FILE - @$(ECHO) $(OBJDIR)/$(LIBRARY).res >> $@ -endif - @$(ECHO) Created $@ - -RC_FLAGS += /D "JDK_FNAME=$(LIBRARY).dll" \ - /D "JDK_INTERNAL_NAME=$(LIBRARY)" \ - /D "JDK_FTYPE=0x2L" - -$(OBJDIR)/$(LIBRARY).res: $(VERSIONINFO_RESOURCE) -ifndef LOCAL_RESOURCE_FILE - @$(prep-target) - $(RC) $(RC_FLAGS) $(CC_OBJECT_OUTPUT_FLAG)$(@) $(VERSIONINFO_RESOURCE) -endif - -# -# Install a .lib file if required. -# -ifeq ($(INSTALL_DOT_LIB), true) -$(ACTUAL_LIBRARY):: $(LIBDIR)/$(LIBRARY).lib - -clean:: - -$(RM) $(LIBDIR)/$(LIBRARY).lib - -$(LIBDIR)/$(LIBRARY).lib:: $(OBJDIR)/$(LIBRARY).lib - $(install-file) - -$(LIBDIR)/$(LIBRARY).dll:: $(OBJDIR)/$(LIBRARY).dll - $(install-file) - -endif # INSTALL_DOT_LIB - -else # PLATFORM - -# -# On Solaris, use mcs to write the version into the comment section of -# the shared library. On other platforms set this to false at the -# make command line. -# -$(ACTUAL_LIBRARY):: $(COMPILE_FILES_o) $(FILES_m) $(FILES_reorder) - @$(prep-target) - @$(ECHO) "STATS: LIBRARY=$(LIBRARY), PRODUCT=$(PRODUCT), _OPT=$(_OPT)" - @$(ECHO) "Rebuilding $@ because of $?" - $(LINKER) $(SHARED_LIBRARY_FLAG) -o $@ $(FILES_o) $(LDLIBS) -ifeq ($(WRITE_LIBVERSION),true) - $(MCS) -d -a "$(FULL_VERSION)" $@ -endif # WRITE_LIBVERSION - -endif # PLATFORM - -# -# Cross check all linted files against each other -# -ifeq ($(PLATFORM),solaris) -lint.errors : $(FILES_ln) - $(LINT.c) $(FILES_ln) $(LDLIBS) -endif - -# -# Class libraries with JNI native methods get a include to the package. -# -ifdef PACKAGE -vpath %.c $(PLATFORM_SRC)/native/$(PKGDIR) -vpath %.c $(SHARE_SRC)/native/$(PKGDIR) -OTHER_INCLUDES += -I$(SHARE_SRC)/native/common -I$(PLATFORM_SRC)/native/common -OTHER_INCLUDES += -I$(SHARE_SRC)/native/$(PKGDIR) \ - -I$(PLATFORM_SRC)/native/$(PKGDIR) -endif - -# -# Clean/clobber rules -# -clean:: - $(RM) -r $(ACTUAL_LIBRARY) - -clobber:: clean - -# -# INCREMENTAL_BUILD means that this workspace will be built over and over -# possibly incrementally. This means tracking the object file dependencies -# on include files so that sources get re-compiled when the include files -# change. When building from scratch and doing a one time build (like -# release engineering or nightly builds) set INCREMENTAL_BUILD=false. -# - -ifeq ($(INCREMENTAL_BUILD),true) - -# -# Workaround: gnumake sometimes says files is empty when it shouldn't -# was: files := $(foreach file, $(wildcard $(OBJDIR)/*.$(DEPEND_SUFFIX)), $(file)) -# -files := $(shell $(LS) $(OBJDIR)/*.$(DEPEND_SUFFIX) 2>/dev/null) - -# -# Only include these files if we have any. -# -ifneq ($(strip $(files)),) - -include $(files) - -endif # files - -endif # INCREMENTAL_BUILD - -# -# Default dependencies -# - -all: build - -build: library - -debug: - $(MAKE) VARIANT=DBG build - -fastdebug: - $(MAKE) VARIANT=DBG FASTDEBUG=true build - -.PHONY: all build debug fastdebug - diff --git a/corba/make/common/Mapfile-vers.gmk b/corba/make/common/Mapfile-vers.gmk deleted file mode 100644 index e4e151f3214..00000000000 --- a/corba/make/common/Mapfile-vers.gmk +++ /dev/null @@ -1,98 +0,0 @@ -# -# Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# -# Makefile for linking with mapfiles. -# -# NOTE: Not using a mapfile will expose all your extern functions and -# extern data symbols as part of your interface, so unless your -# extern names are safe from being mistaken as names from other -# libraries, you better use a mapfile, or use a unique naming -# convention on all your extern symbols. -# -# The mapfile will establish versioning by defining the exported interface. -# -# The mapfile can also force certain .o files or elf sections into the -# the different segments of the resulting library/program image. -# -# The macro FILES_m can contain any number of mapfiles. -# - -# Always make sure 'all' is the default rule -mapfile_default_rule: all - -ifeq ($(PLATFORM), solaris) - -ifeq ($(VARIANT), OPT) - # OPT build MUST have a mapfile? - ifndef FILES_m - FILES_m = mapfile-vers - endif - - # If we are re-ordering functions in this solaris library, we need to make - # sure that -xF is added to the compile lines. This option is critical and - # enables the functions to be reordered. - ifdef FILES_reorder - CFLAGS_OPT += -xF - CXXFLAGS_OPT += -xF - endif - -INIT += $(TEMPDIR)/mapfile-vers - -$(TEMPDIR)/mapfile-vers : $(FILES_m) $(FILES_reorder) - $(prep-target) - $(CAT) $(FILES_m) > $@ - ifdef FILES_reorder - $(SED) -e 's=OUTPUTDIR=$(OUTPUTDIR)=' $(FILES_reorder) >> $@ - endif -endif # VARIANT - -ifndef LDNOMAP - LDMAPFLAGS_OPT = -M$(TEMPDIR)/mapfile-vers - LDMAPFLAGS_DBG = $(FILES_m:%=-M%) -endif - -endif # PLATFORM - - -ifeq ($(PLATFORM), linux) - -ifeq ($(VARIANT), OPT) - # OPT build MUST have a mapfile? - ifndef FILES_m - FILES_m = mapfile-vers - endif -endif # VARIANT - -ifndef LDNOMAP - LDMAPFLAGS_OPT = $(FILES_m:%=-Xlinker -version-script=%) - LDMAPFLAGS_DBG = $(FILES_m:%=-Xlinker -version-script=%) -endif - -endif # PLATFORM - -LDFLAGS_OPT += $(LDMAPFLAGS_OPT) -LDFLAGS_DBG += $(LDMAPFLAGS_DBG) - diff --git a/corba/make/common/Rules.gmk b/corba/make/common/Rules.gmk index ae4633de512..a18978697b4 100644 --- a/corba/make/common/Rules.gmk +++ b/corba/make/common/Rules.gmk @@ -34,7 +34,7 @@ rules_default_rule: all # # Directory set up. (Needed by deploy workspace) # -$(CLASSDESTDIR) $(CLASSHDRDIR) $(OBJDIR) $(OUTPUTDIR) $(BINDIR) $(LIBDIR) $(LIBDIR)/$(LIBARCH) $(TEMPDIR) $(EXTDIR): +$(CLASSDESTDIR) $(OUTPUTDIR) $(TEMPDIR) $(EXTDIR): $(MKDIR) -p $@ # @@ -163,9 +163,6 @@ $(CLASSDESTDIR)/%.class: $(SHARE_SRC)/classes/%.java # List of class files needed FILES_class = $(FILES_java:%.java=$(CLASSDESTDIR)/%.class) -# Got to include exported files. -FILES_class += $(FILES_export:%.java=$(CLASSDESTDIR)/%.class) - # Construct list of java sources we need to compile source_list_prime: @$(MKDIR) -p $(TEMPDIR) @@ -214,50 +211,7 @@ endif classes.clean: packages.clean $(RM) $(JAVA_SOURCE_LIST) -# -# C and C++ make dependencies -# -include $(TOPDIR)/make/common/internal/NativeCompileRules.gmk - -# -# Running Javah to generate stuff into CClassHeaders. -# - -ifdef FILES_export - -CLASSES.export = $(subst /,.,$(FILES_export:%.java=%)) -CLASSES.export += $(subst /,.,$(FILES_export2:%.java=%)) -CLASSES.export += $(subst /,.,$(FILES_export3:%.java=%)) -CLASSES_export = $(FILES_export:%.java=$(CLASSDESTDIR)/%.class) -CLASSES_export += $(FILES_export2:%.java=$(CLASSDESTDIR)/%.class) -CLASSES_export += $(FILES_export3:%.java=$(CLASSDESTDIR)/%.class) - -# Fix when deploy workspace makefiles don't depend on this name -#CLASSHDR_DOTFILE=$(CLASSHDRDIR)/.classheaders - -CLASSHDR_DOTFILE=$(OBJDIR)/.class.headers.$(ARCH) - -classheaders: classes $(CLASSHDR_DOTFILE) - -$(CLASSHDR_DOTFILE): $(CLASSES_export) - $(prep-target) - $(JAVAH_CMD) -d $(CLASSHDRDIR)/ \ - $(CLASSES.export) $(subst $$,\$$,$(EXPORTED_inner)) - @$(java-vm-cleanup) - @$(TOUCH) $@ - -classheaders.clean: - $(RM) -r $(CLASSHDRDIR) $(CLASSHDR_DOTFILE) - -else # FILES_export - -classheaders: classes - -classheaders.clean: - -endif # FILES_export - -clean clobber:: classheaders.clean classes.clean .delete.classlist +clean clobber:: classes.clean .delete.classlist # # Default dependencies @@ -265,12 +219,11 @@ clean clobber:: classheaders.clean classes.clean .delete.classlist all: build -build: classheaders +build: classes default: all .PHONY: all build clean clobber \ .delete.classlist classes .compile.classlist classes.clean \ - classheaders classheaders.clean \ batch_compile diff --git a/corba/make/common/internal/NativeCompileRules.gmk b/corba/make/common/internal/NativeCompileRules.gmk deleted file mode 100644 index 5d9cf729ea6..00000000000 --- a/corba/make/common/internal/NativeCompileRules.gmk +++ /dev/null @@ -1,214 +0,0 @@ -# -# Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# -# Native C/C++ Compile Rules -# - -# -# INCREMENTAL_BUILD: Record the #include file dependencies. -# -# NOTE: We build make include files with the suffix -# $(DEPEND_SUFFIX) on every compilation. These are initially -# created as temp files just in case a ^C kills it in the middle. -# Compiler is smart enough to handle ^C and not create the .o file, or -# is supposed to be that smart, but the .$(DEPEND_SUFFIX) file -# creation here isn't. -# These .$(DEPEND_SUFFIX) files are included by Library.gmk and -# Program.gmk, when they exist (Search for 'make dependencies'). -# - -ifeq ($(INCREMENTAL_BUILD),true) - -$(OBJDIR)/%.$(DEPEND_SUFFIX): %.c - @$(prep-target) - @$(ECHO) "Creating $@" - @$(RM) $@.temp - @$(CC) $(CC_DEPEND) $(CPPFLAGS) $< 2> $(DEV_NULL) | \ - $(CC_DEPEND_FILTER) > $@.temp - @$(MV) $@.temp $@ - -$(OBJDIR)/%.$(DEPEND_SUFFIX): %.cpp - @$(prep-target) - @$(ECHO) "Creating $@" - @$(RM) $@.temp - @$(CXX) $(CC_DEPEND) $(CPPFLAGS) $(CXXFLAGS) $< 2> $(DEV_NULL) | \ - $(CC_DEPEND_FILTER) > $@.temp - @$(MV) $@.temp $@ - -endif # INCREMENTAL_BUILD - -# -# C, C++, asm files. -# -# Normal or parallel compile rule is the same, but batch compiles require -# we save up the sources files that use the same compile line so that we -# can do one compile line. -# - -ifneq ($(COMPILE_APPROACH), batch) - -$(OBJDIR)/%.$(OBJECT_SUFFIX): %.c - @$(prep-target) - $(COMPILE.c) $(CC_OBJECT_OUTPUT_FLAG)$@ $(CFLAGS_GPROF) $< - @$(check-conventions) - -$(OBJDIR)/%.$(OBJECT_SUFFIX): %.cpp - @$(prep-target) - $(COMPILE.cc) $(CC_OBJECT_OUTPUT_FLAG)$@ $(CFLAGS_GPROF) $< - @$(check-conventions) - -else - - # - # Batch compiling might be faster if the compiler was smart about recognizing - # optimization opportunities available when all files are being compiled - # the same way. Unfortunately this is rare. - # Automatic pre-compiled headers (pch) might be a possibility so we - # add any auto pch options here. - # So we save all the source files that have the same compile line as the - # first file. A normal compile pass is made after the batch compile - # to catch anything missed. - # If the compilers had a -o option that allowed us to direct where to - # write the object files to, then we would not need to save the object - # file list or move them from the make directory to the build directory. - # - - # Source names - COMPILE_LIST.c = $(OBJDIR)/.source_names_c - COMPILE_LIST.cpp = $(OBJDIR)/.source_names_cpp - - # Object file list - COMPILE_OBJ_LIST.c = $(OBJDIR)/.obj_names_c - COMPILE_OBJ_LIST.cpp = $(OBJDIR)/.obj_names_cpp - - # The compile line - COMPILE_BATCH.c = $(OBJDIR)/.compile_c - COMPILE_BATCH.cpp = $(OBJDIR)/.compile_cpp - - # The compile line for the current target - THIS_COMPILE_BATCH.c = $(COMPILE_BATCH.c)-$(@F) - THIS_COMPILE_BATCH.cpp = $(COMPILE_BATCH.cpp)-$(@F) - -$(OBJDIR)/%.$(OBJECT_SUFFIX): %.c - @$(prep-target) - @$(ECHO) "$(COMPILE.c) $(CFLAGS_GPROF)" > $(THIS_COMPILE_BATCH.c) - @if [ ! -s $(COMPILE_BATCH.c) ] ; then \ - $(CP) $(THIS_COMPILE_BATCH.c) $(COMPILE_BATCH.c) ; \ - $(ECHO) $< > $(COMPILE_LIST.c); \ - $(ECHO) $(@F) > $(COMPILE_OBJ_LIST.c); \ - elif [ "`$(DIFF) -w -b $(THIS_COMPILE_BATCH.c) $(COMPILE_BATCH.c)`" \ - = "" ] ; then \ - $(ECHO) $< >> $(COMPILE_LIST.c); \ - $(ECHO) $(@F) >> $(COMPILE_OBJ_LIST.c); \ - fi - @$(RM) $(THIS_COMPILE_BATCH.c) - @$(check-conventions) - -$(OBJDIR)/%.$(OBJECT_SUFFIX): %.cpp - @$(prep-target) - @$(ECHO) "$(COMPILE.cpp) $(CFLAGS_GPROF)" > $(THIS_COMPILE_BATCH.cpp) - @if [ ! -s $(COMPILE_BATCH.cpp) ] ; then \ - $(CP) $(THIS_COMPILE_BATCH.cpp) $(COMPILE_BATCH.cpp) ; \ - $(ECHO) $< > $(COMPILE_LIST.cpp); \ - $(ECHO) $(@F) > $(COMPILE_OBJ_LIST.cpp); \ - elif [ "`$(DIFF) -w -b $(THIS_COMPILE_BATCH.cpp) $(COMPILE_BATCH.cpp)`"\ - = "" ] ; then \ - $(ECHO) $< >> $(COMPILE_LIST.cpp); \ - $(ECHO) $(@F) >> $(COMPILE_OBJ_LIST.cpp); \ - fi - @$(RM) $(THIS_COMPILE_BATCH.cpp) - @$(check-conventions) - -batch_compile: $(FILES_o) - @$(ECHO) "Doing batch compilations" - @if [ -s $(COMPILE_LIST.c) ] ; then \ - $(ECHO) "$(COMPILE.c) $(CFLAGS_GPROF) $(AUTOMATIC_PCH_OPTION) \ - `$(CAT) $(COMPILE_LIST.c)`" ; \ - ( $(COMPILE.c) $(CFLAGS_GPROF) $(AUTOMATIC_PCH_OPTION) \ - `$(CAT) $(COMPILE_LIST.c)` && \ - $(ECHO) "$(MV) `$(CAT) $(COMPILE_OBJ_LIST.c)` $(OBJDIR)" && \ - $(MV) `$(CAT) $(COMPILE_OBJ_LIST.c)` $(OBJDIR) ) || exit 1 ; \ - fi - @if [ -s $(COMPILE_LIST.cpp) ] ; then \ - $(ECHO) "$(COMPILE.cpp) $(CFLAGS_GPROF) $(AUTOMATIC_PCH_OPTION) \ - `$(CAT) $(COMPILE_LIST.cpp)`" ; \ - ( $(COMPILE.cpp) $(CFLAGS_GPROF) $(AUTOMATIC_PCH_OPTION) \ - `$(CAT) $(COMPILE_LIST.cpp)` && \ - $(ECHO) "$(MV) `$(CAT) $(COMPILE_OBJ_LIST.cpp)` $(OBJDIR)" && \ - $(MV) `$(CAT) $(COMPILE_OBJ_LIST.cpp)` $(OBJDIR) ) || exit 1 ; \ - fi - @$(RM) $(COMPILE_BATCH.c) $(COMPILE_LIST.c) $(COMPILE_OBJ_LIST.c) - @$(RM) $(COMPILE_BATCH.cpp) $(COMPILE_LIST.cpp) $(COMPILE_OBJ_LIST.cpp) - -endif - -# newer as does not handle c++ style comments -$(OBJDIR)/%.$(OBJECT_SUFFIX): %.s - ifneq ($(CC_VERSION), gcc) - @$(prep-target) - $(COMPILE.s) $(CC_OBJECT_OUTPUT_FLAG)$@ $< - else - @$(prep-target) - $(CPP) -x assembler-with-cpp $< | $(COMPILE.s) -o $@ - endif - @$(check-conventions) - -# -# Quick hack for making the compiler generate just the assembly file. -# $ gnumake obj/sparc/myfile.s -# -$(OBJDIR)/%.s: %.c - @$(prep-target) - $(COMPILE.c) $(CC_OBJECT_OUTPUT_FLAG)$@ -S $< - @$(check-conventions) - -# remove the intermediate files from the directories. -# (If VARIANT=OPT, this removes all debug and fastdebug files too) -clobber clean:: - $(RM) -r $(OBJDIR) - $(RM) -r $(OBJDIR)_* - -# -# Lint support -# (The 'lint' rule below is an older rule not using the .$(LINT_SUFFIX) files) -# - -ifeq ($(PLATFORM), solaris) -$(OBJDIR)/%.$(LINT_SUFFIX): %.c - @$(prep-target) - $(LINT.c) -dirout=$(OBJDIR) -c $< -lint.clean: - $(RM) $(OBJDIR)/*.$(LINT_SUFFIX) -# Old rule -lint: $(FILES_c) - ifneq ($(FILES_c),) - $(LINT.c) -Ncheck -Nlevel=3 $? $(LDLIBS) > lint.$(ARCH) 2>&1 - endif -endif - -.PHONY: batch_compile - - diff --git a/corba/make/common/shared/Compiler-gcc.gmk b/corba/make/common/shared/Compiler-gcc.gmk deleted file mode 100644 index 3c3604b3c72..00000000000 --- a/corba/make/common/shared/Compiler-gcc.gmk +++ /dev/null @@ -1,119 +0,0 @@ -# -# Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# -# GCC Compiler settings -# - -COMPILER_NAME=GCC - -ifeq ($(PLATFORM), windows) - - # Settings specific to Windows, pretty stale, hasn't been used - CC = $(COMPILER_PATH)gcc - CPP = $(COMPILER_PATH)gcc -E - CXX = $(COMPILER_PATH)g++ - CCC = $(COMPILER_PATH)g++ - LIBEXE = $(COMPILER_PATH)lib - LINK = $(COMPILER_PATH)link - RC = $(MSDEVTOOLS_PATH)link - LINK32 = $(LINK) - RSC = $(RC) - # unset any GNU Make settings of MFLAGS and MAKEFLAGS which may mess up nmake - NMAKE = MFLAGS= MAKEFLAGS= $(COMPILER_PATH)nmake -nologo - ifeq ($(ARCH_DATA_MODEL), 32) - CC_VER = UNKNOWN - CC_TYPE = UNKNOWN - else - CC_VER = UNKNOWN - CC_TYPE = UNKNOWN - endif - _LINK_VER :=$(shell $(LINK) 2>&1 | $(HEAD) -n 1) - LINK_VER :=$(call GetVersion,"$(_LINK_VER)") - -endif - -ifeq ($(PLATFORM), linux) - - # Settings specific to Linux - CC = $(COMPILER_PATH)gcc - CPP = $(COMPILER_PATH)gcc -E - # statically link libstdc++ before C++ ABI is stablized on Linux - STATIC_CXX = true - ifeq ($(STATIC_CXX),true) - # g++ always dynamically links libstdc++, even we use "-Wl,-Bstatic -lstdc++" - # We need to use gcc to statically link the C++ runtime. gcc and g++ use - # the same subprocess to compile C++ files, so it is OK to build using gcc. - CXX = $(COMPILER_PATH)gcc - else - CXX = $(COMPILER_PATH)g++ - endif - ifeq ($(ZERO_BUILD), true) - # zero - REQUIRED_CC_VER = 3.2 - REQUIRED_GCC_VER = 3.2.* - else - ifneq ("$(findstring sparc,$(ARCH))", "") - # sparc or sparcv9 - REQUIRED_CC_VER = 4.0 - else - ifeq ($(ARCH_DATA_MODEL), 32) - # i586 - REQUIRED_CC_VER = 3.2 - else - ifeq ($(ARCH), amd64) - # amd64 - REQUIRED_CC_VER = 3.2 - endif - ifeq ($(ARCH), ia64) - # ia64 - REQUIRED_CC_VER = 3.2 - endif - endif - endif - endif - # Option used to create a shared library - SHARED_LIBRARY_FLAG = -shared -mimpure-text - SUN_COMP_VER := $(shell $(CC) --verbose 2>&1 ) - -endif - -ifeq ($(PLATFORM), solaris) - - # Settings specific to Solaris - CC = $(COMPILER_PATH)gcc - CPP = $(COMPILER_PATH)gcc -E - CXX = $(COMPILER_PATH)g++ - REQUIRED_CC_VER = 3.2 - - # Option used to create a shared library - SHARED_LIBRARY_FLAG = -G - -endif - -# Get gcc version -_CC_VER :=$(shell $(CC) -dumpversion 2>&1 ) -CC_VER :=$(call GetVersion,"$(_CC_VER)") - diff --git a/corba/make/common/shared/Compiler-msvc.gmk b/corba/make/common/shared/Compiler-msvc.gmk deleted file mode 100644 index ed7c281f714..00000000000 --- a/corba/make/common/shared/Compiler-msvc.gmk +++ /dev/null @@ -1,186 +0,0 @@ -# -# Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# -# MSVC Compiler settings -# - -ifeq ($(PLATFORM), windows) - CC = $(COMPILER_PATH)cl - CPP = $(COMPILER_PATH)cl - CXX = $(COMPILER_PATH)cl - CCC = $(COMPILER_PATH)cl - LIBEXE = $(COMPILER_PATH)lib - LINK = $(COMPILER_PATH)link - RC = $(MSDEVTOOLS_PATH)rc - LINK32 = $(LINK) - RSC = $(RC) - - # Fill in unknown values - COMPILER_NAME=Unknown MSVC Compiler - COMPILER_VERSION= - REQUIRED_CC_VER= - REQUIRED_LINK_VER= - - # unset any GNU Make settings of MFLAGS and MAKEFLAGS which may mess up nmake - NMAKE = MFLAGS= MAKEFLAGS= $(COMPILER_PATH)nmake -nologo - - # Compiler version and type (Always get word after "Version") - ifndef CC_VER - CC_VER := $(shell $(CC) 2>&1 | $(HEAD) -n 1 | $(SED) 's/.*\(Version.*\)/\1/' | $(NAWK) '{print $$2}') - export CC_VER - endif - - # SDK-64 and MSVC6 put REBASE.EXE in a different places - go figure... - ifeq ($(ARCH_DATA_MODEL), 32) - ifndef LINK_VER - LINK_VER := $(shell $(LINK) | $(HEAD) -n 1 | $(NAWK) '{print $$6}') - export LINK_VER - endif - CC_MAJORVER :=$(call MajorVersion,$(CC_VER)) - ifeq ($(CC_MAJORVER), 13) - # This should be: CC_VER=13.10.3077 LINK_VER=7.10.3077 - REQUIRED_CC_VER = 13.10.3077 - REQUIRED_LINK_VER = 7.10.3077 - COMPILER_NAME=Visual Studio .NET 2003 Professional C++ - COMPILER_VERSION=VS2003 - REBASE = $(COMPILER_PATH)../../Common7/Tools/Bin/rebase - MTL = $(COMPILER_PATH)../../Common7/Tools/Bin/midl - ifndef COMPILER_PATH - COMPILER_PATH := $(error COMPILER_PATH cannot be empty here) - endif - endif - ifeq ($(CC_MAJORVER), 14) - # This should be: CC_VER=14.00.50727.42 LINK_VER=8.00.50727.42 - REQUIRED_CC_VER = 14.00.50727.42 - REQUIRED_LINK_VER = 8.00.50727.42 - COMPILER_NAME=Visual Studio 8 - COMPILER_VERSION=VS2005 - REBASE = $(COMPILER_PATH)../../Common8/Tools/Bin/rebase - MTL = $(COMPILER_PATH)../../Common8/Tools/Bin/midl - ifndef COMPILER_PATH - COMPILER_PATH := $(error COMPILER_PATH cannot be empty here) - endif - endif - ifeq ($(CC_MAJORVER), 15) - # This should be: CC_VER=15.00.21022.08 LINK_VER=9.00.21022.08 - REQUIRED_CC_VER = 15.00.21022.08 - REQUIRED_LINK_VER = 9.00.21022.08 - COMPILER_NAME=Visual Studio 9 - COMPILER_VERSION=VS2008 - #rebase and midl moved out of Visual Studio into the SDK: - REBASE = $(MSDEVTOOLS_PATH)/rebase - MTL = $(MSDEVTOOLS_PATH)/midl.exe - ifndef COMPILER_PATH - COMPILER_PATH := $(error COMPILER_PATH cannot be empty here) - endif - endif - ifeq ($(CC_MAJORVER), 16) - # This should be: CC_VER=16.00.30319.01 LINK_VER=10.00.30319.01 - REQUIRED_CC_VER = 16.00.30319.01 - REQUIRED_LINK_VER = 10.00.30319.01 - COMPILER_NAME=Visual Studio 10 - COMPILER_VERSION=VS2010 - #rebase and midl moved out of Visual Studio into the SDK: - REBASE = $(MSDEVTOOLS_PATH)/rebase - MTL = $(MSDEVTOOLS_PATH)/midl.exe - ifndef COMPILER_PATH - COMPILER_PATH := $(error COMPILER_PATH cannot be empty here) - endif - endif - else - # else ARCH_DATA_MODEL is 64 - ifndef LINK_VER - LINK_VER := $(shell $(LINK) | $(HEAD) -n 1 | $(NAWK) '{print $$6}') - export LINK_VER - endif - CC_MAJORVER :=$(call MajorVersion,$(CC_VER)) - CC_MINORVER :=$(call MinorVersion,$(CC_VER)) - CC_MICROVER :=$(call MicroVersion,$(CC_VER)) - ifeq ($(ARCH), ia64) - REQUIRED_CC_VER = 13.00.9337.7 - REQUIRED_LINK_VER = 7.00.9337.7 - endif - ifeq ($(ARCH), amd64) - REQUIRED_CC_VER = 14.00.40310.41 - REQUIRED_LINK_VER = 8.00.40310.39 - endif - ifeq ($(CC_MAJORVER), 13) - ifeq ($(ARCH), ia64) - # This should be: CC_VER=13.00.9337.7 LINK_VER=7.00.9337.7 - COMPILER_NAME=Microsoft Platform SDK - November 2001 Edition - COMPILER_VERSION=VS2003 - endif - endif - ifeq ($(CC_MAJORVER), 14) - ifeq ($(ARCH), amd64) - ifeq ($(CC_MICROVER), 30701) - # This should be: CC_VER=14.00.30701 LINK_VER=8.00.30701 - # WARNING: it says 14, but it is such an early build it doesn't - # have all the VS2005 compiler option changes, so treat - # this like a VS2003 compiler. - COMPILER_NAME=Microsoft Platform SDK - February 2003 Edition - COMPILER_VERSION=VS2003 - else - # This should be: CC_VER=14.00.40310.41 LINK_VER=8.00.40310.39 - COMPILER_NAME=Microsoft Platform SDK - April 2005 Edition (3790.1830) - COMPILER_VERSION=VS2005 - endif - endif - endif - ifeq ($(CC_MAJORVER), 15) - # This should be: CC_VER=15.00.21022.8 LINK_VER=9.00.21022.8 - REQUIRED_CC_VER = 15.00.21022.8 - REQUIRED_LINK_VER = 9.00.21022.8 - COMPILER_NAME=Windows SDK 6.1 Visual Studio 9 - COMPILER_VERSION=VS2008 - RC = $(MSSDK61)/bin/x64/rc - REBASE = $(MSSDK61)/bin/x64/rebase - else - ifeq ($(CC_MAJORVER), 16) - # This should be: CC_VER=16.00.30319.01 LINK_VER=9.00.30319.01 - REQUIRED_CC_VER = 16.00.30319.01 - REQUIRED_LINK_VER = 10.00.30319.01 - COMPILER_NAME=Microsoft Visual Studio 10 - COMPILER_VERSION=VS2010 - RC = $(MSSDK7)/bin/x64/rc - REBASE = $(MSSDK7)/bin/x64/rebase - else - # This will cause problems if ALT_COMPILER_PATH is defined to "" - # which is a directive to use the PATH. - REBASE = $(COMPILER_PATH)../REBASE - endif - endif - ifndef COMPILER_PATH - COMPILER_PATH := $(error COMPILER_PATH cannot be empty here) - endif - endif - ifndef COMPILER_VERSION - COMPILER_VERSION := $(error COMPILER_VERSION cannot be empty here) - endif - # Shared library generation flag - SHARED_LIBRARY_FLAG = -LD -endif - diff --git a/corba/make/common/shared/Compiler-sun.gmk b/corba/make/common/shared/Compiler-sun.gmk deleted file mode 100644 index 3e4e6879691..00000000000 --- a/corba/make/common/shared/Compiler-sun.gmk +++ /dev/null @@ -1,69 +0,0 @@ -# -# Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# -# Sun Studio Compiler settings -# - -COMPILER_NAME=Sun Studio - -# Sun Studio Compiler settings specific to Solaris -ifeq ($(PLATFORM), solaris) - COMPILER_VERSION=SS12 - REQUIRED_CC_VER=5.9 - CC = $(COMPILER_PATH)cc - CPP = $(COMPILER_PATH)cc -E - CXX = $(COMPILER_PATH)CC - LINT = $(COMPILER_PATH)lint - # Option used to create a shared library - SHARED_LIBRARY_FLAG = -G -endif - -# Sun Studio Compiler settings specific to Linux -ifeq ($(PLATFORM), linux) - # This has not been tested - COMPILER_VERSION=SS12 - REQUIRED_CC_VER=5.9 - CC = $(COMPILER_PATH)cc - CPP = $(COMPILER_PATH)cc -E - CXX = $(COMPILER_PATH)CC - LINT = $(COMPILER_PATH)lint - # statically link libstdc++ before C++ ABI is stablized on Linux - STATIC_CXX = true - ifeq ($(STATIC_CXX),true) - # CC always dynamically links libstdc++, even we use "-Wl,-Bstatic -lstdc++" - # We need to use cc to statically link the C++ runtime. - CXX = $(COMPILER_PATH)cc - else - CXX = $(COMPILER_PATH)CC - endif - # Option used to create a shared library - SHARED_LIBRARY_FLAG = -G -endif - -# Get compiler version -_CC_VER :=$(shell $(CC) -V 2>&1 | $(HEAD) -n 1) -CC_VER :=$(call GetVersion,"$(_CC_VER)") - diff --git a/corba/make/common/shared/Defs-java.gmk b/corba/make/common/shared/Defs-java.gmk index 57e8642a52f..8d7531fe3e4 100644 --- a/corba/make/common/shared/Defs-java.gmk +++ b/corba/make/common/shared/Defs-java.gmk @@ -42,7 +42,7 @@ else endif # -# All java tools (javac, javah, and javadoc) run faster with certain java +# All java tools (javac and javadoc) run faster with certain java # options, this macro should be used with all these tools. # In particular, the client VM makes these tools run faster when # it's available. @@ -134,21 +134,14 @@ JAVACFLAGS += -encoding ascii JAVACFLAGS += -classpath $(BOOTDIR)/lib/tools.jar JAVACFLAGS += $(OTHER_JAVACFLAGS) -# Needed for javah -JAVAHFLAGS += -classpath $(CLASSBINDIR) - # Langtools ifdef LANGTOOLS_DIST JAVAC_JAR = $(LANGTOOLS_DIST)/bootstrap/lib/javac.jar - JAVAH_JAR = $(LANGTOOLS_DIST)/bootstrap/lib/javah.jar JAVADOC_JAR = $(LANGTOOLS_DIST)/bootstrap/lib/javadoc.jar DOCLETS_JAR = $(LANGTOOLS_DIST)/bootstrap/lib/doclets.jar JAVAC_CMD = $(BOOT_JAVA_CMD) \ "-Xbootclasspath/p:$(JAVAC_JAR)" \ -jar $(JAVAC_JAR) $(JAVACFLAGS) - JAVAH_CMD = $(BOOT_JAVA_CMD) \ - "-Xbootclasspath/p:$(JAVAH_JAR)$(CLASSPATH_SEPARATOR)$(JAVADOC_JAR)$(CLASSPATH_SEPARATOR)$(JAVAC_JAR)" \ - -jar $(JAVAH_JAR) $(JAVAHFLAGS) JAVADOC_CMD = $(BOOT_JAVA_CMD) \ "-Xbootclasspath/p:$(JAVADOC_JAR)$(CLASSPATH_SEPARATOR)$(JAVAC_JAR)$(CLASSPATH_SEPARATOR)$(DOCLETS_JAR)" \ -jar $(JAVADOC_JAR) @@ -156,8 +149,6 @@ else # If no explicit tools, use boot tools (add VM flags in this case) JAVAC_CMD = $(JAVA_TOOLS_DIR)/javac $(JAVAC_JVM_FLAGS) \ $(JAVACFLAGS) - JAVAH_CMD = $(JAVA_TOOLS_DIR)/javah \ - $(JAVAHFLAGS) JAVADOC_CMD = $(JAVA_TOOLS_DIR)/javadoc $(JAVA_TOOLS_FLAGS:%=-J%) endif diff --git a/corba/make/common/shared/Defs-linux.gmk b/corba/make/common/shared/Defs-linux.gmk index c9b931f6b08..9db85a39ba7 100644 --- a/corba/make/common/shared/Defs-linux.gmk +++ b/corba/make/common/shared/Defs-linux.gmk @@ -94,14 +94,6 @@ else JDK_DEVTOOLS_DIR =$(SLASH_JAVA)/devtools endif -# COMPILER_PATH: path to where the compiler and tools are installed. -# NOTE: Must end with / so that it could be empty, allowing PATH usage. -ifneq "$(origin ALT_COMPILER_PATH)" "undefined" - COMPILER_PATH :=$(call PrefixPath,$(ALT_COMPILER_PATH)) -else - COMPILER_PATH =/usr/bin/ -endif - # DEVTOOLS_PATH: for other tools required for building (such as zip, etc.) # NOTE: Must end with / so that it could be empty, allowing PATH usage. ifneq "$(origin ALT_DEVTOOLS_PATH)" "undefined" diff --git a/corba/make/common/shared/Defs-solaris.gmk b/corba/make/common/shared/Defs-solaris.gmk index 61d218c635c..7f0abf6a790 100644 --- a/corba/make/common/shared/Defs-solaris.gmk +++ b/corba/make/common/shared/Defs-solaris.gmk @@ -86,24 +86,6 @@ else JDK_DEVTOOLS_DIR =$(SLASH_JAVA)/devtools endif -# COMPILER_PATH: path to where the compiler and tools are installed. -# NOTE: Must end with / so that it could be empty, allowing PATH usage. -ifneq "$(origin ALT_COMPILER_PATH)" "undefined" - COMPILER_PATH :=$(call PrefixPath,$(ALT_COMPILER_PATH)) -else - # Careful here, COMPILER_VERSION may not be defined yet (see Compiler.gmk) - # If the place where we keep a set of Sun Studio compilers doesn't exist, - # try and use /opt/SUNWspro, the default location for the SS compilers. - # (DirExists checks for this path twice, an automount double check) - _SUNSTUDIO_SET_ROOT=$(JDK_DEVTOOLS_DIR)/$(ARCH_FAMILY)/SUNWspro - SUNSTUDIO_SET_ROOT:=$(call DirExists,$(_SUNSTUDIO_SET_ROOT),$(_SUNSTUDIO_SET_ROOT),) - ifneq ($(SUNSTUDIO_SET_ROOT),) - COMPILER_PATH =$(SUNSTUDIO_SET_ROOT)/$(COMPILER_VERSION)/bin/ - else - COMPILER_PATH =/opt/SUNWspro/bin/ - endif -endif - # DEVTOOLS_PATH: for other tools required for building (such as zip, etc.) # NOTE: Must end with / so that it could be empty, allowing PATH usage. ifneq "$(origin ALT_DEVTOOLS_PATH)" "undefined" diff --git a/corba/make/common/shared/Defs-windows.gmk b/corba/make/common/shared/Defs-windows.gmk index 41fcce6ce7b..559317a744e 100644 --- a/corba/make/common/shared/Defs-windows.gmk +++ b/corba/make/common/shared/Defs-windows.gmk @@ -31,7 +31,6 @@ # Level: Default is 3, 0 means none, 4 is the most but may be unreliable # Some makefiles may have set this to 0 to turn off warnings completely, # which also effectively creates a COMPILER_WARNINGS_FATAL=false situation. -# Program.gmk may turn this down to 2 (building .exe's). # Windows 64bit platforms are less likely to be warning free. # Historically, Windows 32bit builds should be mostly warning free. ifndef COMPILER_WARNING_LEVEL @@ -74,7 +73,7 @@ override INCREMENTAL_BUILD = false # The ALT values should never really have spaces or use \. # Suspect these environment variables to have spaces and/or \ characters: # SYSTEMROOT, SystemRoot, WINDIR, windir, PROGRAMFILES, ProgramFiles, -# MSTOOLS, Mstools, MSSDK, MSSdk, VC71COMNTOOLS, +# VC71COMNTOOLS, # MSVCDIR, MSVCDir. # So use $(subst \,/,) on them first adding quotes and placing them in # their own variable assigned with :=, then use FullPath. @@ -201,124 +200,6 @@ ifndef SHORTPROGRAMFILES export SHORTPROGRAMFILES endif -# Compilers, SDK, and Visual Studio (MSDEV) [32bit is different from 64bit] -ifeq ($(ARCH_DATA_MODEL), 32) - ifndef SHORTMSVCDIR - # Try looking in MSVCDIR or MSVCDir area first (set by vcvars32.bat) - ifdef MSVCDIR - xMSVCDIR :="$(subst \,/,$(MSVCDIR))" - SHORTMSVCDIR :=$(call FullPath,$(xMSVCDIR)) - else - ifdef MSVCDir - xMSVCDIR :="$(subst \,/,$(MSVCDir))" - SHORTMSVCDIR :=$(call FullPath,$(xMSVCDIR)) - else - ifneq ($(SHORTPROGRAMFILES),) - xMSVCDIR :="$(SHORTPROGRAMFILES)/Microsoft Visual Studio .NET 2003/Vc7" - SHORTMSVCDIR :=$(call FullPath,$(xMSVCDIR)) - endif - endif - endif - ifneq ($(subst MSDev98,OLDOLDOLD,$(SHORTMSVCDIR)),$(SHORTMSVCDIR)) - SHORTMSVCDIR := - endif - # If we still don't have it, look for VS100COMNTOOLS, setup by installer? - ifeq ($(SHORTMSVCDIR),) - ifdef VS100COMNTOOLS # /Common/Tools directory, use ../../Vc - xVS100COMNTOOLS :="$(subst \,/,$(VS100COMNTOOLS))" - _vs100tools :=$(call FullPath,$(xVS100COMNTOOLS)) - endif - ifneq ($(_vs100tools),) - SHORTMSVCDIR :=$(_vs100tools)/../../Vc - endif - endif - export SHORTMSVCDIR - # If we still don't have it, look for VS71COMNTOOLS, setup by installer? - ifeq ($(SHORTMSVCDIR),) - ifdef VS71COMNTOOLS # /Common/Tools directory, use ../../Vc7 - xVS71COMNTOOLS :="$(subst \,/,$(VS71COMNTOOLS))" - _vs71tools :=$(call FullPath,$(xVS71COMNTOOLS)) - endif - ifneq ($(_vs71tools),) - SHORTMSVCDIR :=$(_vs71tools)/../../Vc7 - endif - endif - export SHORTMSVCDIR - endif - ifneq ($(SHORTMSVCDIR),) - SHORTCOMPILERBIN :=$(SHORTMSVCDIR)/Bin - SHORTPSDK :=$(SHORTMSVCDIR)/PlatformSDK - export SHORTCOMPILERBIN - export SHORTPSDK - endif -endif - -# The Microsoft Platform SDK installed by itself -ifneq ($(SHORTPROGRAMFILES),) - ifndef SHORTPSDK - xPSDK :="$(SHORTPROGRAMFILES)/Microsoft Platform SDK" - SHORTPSDK :=$(call FullPath,$(xPSDK)) - ifeq ($(SHORTPSDK),) - xPSDK :="$(SHORTPROGRAMFILES)/Microsoft SDK" - SHORTPSDK :=$(call FullPath,$(xMSSDK)) - endif - export SHORTPSDK - endif -endif - -# If no SDK found yet, look in other places -ifndef SHORTPSDK - ifdef MSSDK - xMSSDK :="$(subst \,/,$(MSSDK))" - SHORTPSDK :=$(call FullPath,$(xMSSDK)) - else - ifdef MSSdk - xMSSDK :="$(subst \,/,$(MSSdk))" - SHORTPSDK :=$(call FullPath,$(xMSSDK)) - endif - endif - export SHORTPSDK -endif - -# Compilers for 64bit are from SDK -ifeq ($(ARCH_DATA_MODEL), 64) - ifndef SHORTCOMPILERBIN - ifdef VS100COMNTOOLS # /Common7/Tools directory, use ../../Vc - xVS100COMNTOOLS :="$(subst \,/,$(VS100COMNTOOLS))" - _vs100tools :=$(call FullPath,$(xVS100COMNTOOLS)) - endif - ifneq ($(_vs100tools),) - SHORTCOMPILERBIN :=$(_vs100tools)/../../Vc/bin/amd64 - xMSSDK70 :="C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/" - MSSDK7 :=$(call FullPath,$(xMSSDK70)) - export MSSDK7 - else - xMSSDK61 :="C:/Program Files/Microsoft SDKs/Windows/v6.1/" - MSSDK61 :=$(call FullPath,$(xMSSDK61)) - xVS2008 :="C:/Program Files (x86)/Microsoft Visual Studio 9.0/" - _vs2008 :=$(call FullPath,$(xVS2008)) - ifneq ($(_vs2008),) - ifeq ($(ARCH), ia64) - SHORTCOMPILERBIN :=$(_vs2008)/VC/Bin/x86_ia64 - endif - ifeq ($(ARCH), amd64) - SHORTCOMPILERBIN :=$(_vs2008)/VC/Bin/$(ARCH) - endif - else - ifneq ($(SHORTPSDK),) - ifeq ($(ARCH), ia64) - SHORTCOMPILERBIN :=$(SHORTPSDK)/Bin/Win64 - endif - ifeq ($(ARCH), amd64) - SHORTCOMPILERBIN :=$(SHORTPSDK)/Bin/Win64/x86/$(ARCH) - endif - endif - endif - endif - export SHORTCOMPILERBIN - endif -endif - # Location on system where jdk installs might be ifneq ($(SHORTPROGRAMFILES),) USRJDKINSTANCES_PATH =$(SHORTPROGRAMFILES)/Java @@ -356,55 +237,6 @@ ifndef JDK_DEVTOOLS_DIR export JDK_DEVTOOLS_DIR endif -# COMPILER_PATH: path to where the compiler and tools are installed. -# NOTE: Must end with / so that it could be empty, allowing PATH usage. -ifndef COMPILER_PATH - ifdef ALT_COMPILER_PATH - xALT_COMPILER_PATH :="$(subst \,/,$(ALT_COMPILER_PATH))" - fxALT_COMPILER_PATH :=$(call FullPath,$(xALT_COMPILER_PATH)) - COMPILER_PATH :=$(call PrefixPath,$(fxALT_COMPILER_PATH)) - else - COMPILER_PATH :=$(call PrefixPath,$(SHORTCOMPILERBIN)) - endif - COMPILER_PATH :=$(call AltCheckSpaces,COMPILER_PATH) - export COMPILER_PATH -endif - -# MSDEVTOOLS_PATH: path to where the additional MS Compiler tools are. -# NOTE: Must end with / so that it could be empty, allowing PATH usage. -ifndef MSDEVTOOLS_PATH - ifdef ALT_MSDEVTOOLS_PATH - xALT_MSDEVTOOLS_PATH :="$(subst \,/,$(ALT_MSDEVTOOLS_PATH))" - fxALT_MSDEVTOOLS_PATH :=$(call FullPath,$(xALT_MSDEVTOOLS_PATH)) - MSDEVTOOLS_PATH :=$(call PrefixPath,$(fxALT_MSDEVTOOLS_PATH)) - else - ifeq ($(ARCH_DATA_MODEL), 64) - ifdef MSTOOLS - xMSTOOLS :="$(subst \,/,$(MSTOOLS))" - _ms_tools :=$(call FullPath,$(xMSTOOLS)) - else - ifdef Mstools - xMSTOOLS :="$(subst \,/,$(Mstools))" - _ms_tools :=$(call FullPath,$(xMSTOOLS)) - else - _ms_tools := - endif - endif - ifneq ($(_ms_tools),) - _ms_tools_bin :=$(_ms_tools)/Bin - else - # Assumes compiler bin is .../Bin/win64/x86/AMD64, rc.exe is 3 levels up - _ms_tools_bin :=$(SHORTCOMPILERBIN)/../../.. - endif - else - _ms_tools_bin :=$(SHORTCOMPILERBIN) - endif - MSDEVTOOLS_PATH :=$(call PrefixPath,$(_ms_tools_bin)) - endif - MSDEVTOOLS_PATH:=$(call AltCheckSpaces,MSDEVTOOLS_PATH) - export MSDEVTOOLS_PATH -endif - # DEVTOOLS_PATH: for other tools required for building (such as zip, etc.) # NOTE: Must end with / so that it could be empty, allowing PATH usage. ifndef DEVTOOLS_PATH diff --git a/corba/make/common/shared/Defs.gmk b/corba/make/common/shared/Defs.gmk index 1875bd95fd7..af1456bab97 100644 --- a/corba/make/common/shared/Defs.gmk +++ b/corba/make/common/shared/Defs.gmk @@ -51,7 +51,7 @@ # Get shared system utilities macros defined include $(BUILDDIR)/common/shared/Defs-utils.gmk -# Assumes ARCH, PLATFORM, ARCH_VM_SUBDIR, etc. have been defined. +# Assumes ARCH, PLATFORM, etc. have been defined. # Simple pwd path define PwdPath @@ -157,7 +157,6 @@ endef _check_values:=\ $(call CheckValue,ARCH,),\ $(call CheckValue,ARCH_DATA_MODEL,),\ -$(call CheckValue,ARCH_VM_SUBDIR,),\ $(call CheckValue,VARIANT,),\ $(call CheckValue,PLATFORM,) @@ -194,21 +193,15 @@ endif # can be OPT or DBG, default is OPT # Determine the extra pattern to add to the release name for debug/fastdebug. # Determine the JDK_IMPORT_VARIANT, so we get the right VM files copied over. -# Determine suffix for obj directory or OBJDIR, for .o files. -# (by keeping .o files separate, just .o files, they don't clobber each -# other, however, the library files will clobber each other). # ifeq ($(VARIANT), DBG) BUILD_VARIANT_RELEASE=-debug - OBJDIRNAME_SUFFIX=_g else BUILD_VARIANT_RELEASE= - OBJDIRNAME_SUFFIX= endif ifeq ($(FASTDEBUG), true) VARIANT=DBG BUILD_VARIANT_RELEASE=-fastdebug - OBJDIRNAME_SUFFIX=_gO _JDK_IMPORT_VARIANT=/fastdebug endif @@ -330,6 +323,4 @@ BINDIR = $(OUTPUTDIR)/bin$(ISA_DIR) # Absolute path to output directory ABS_OUTPUTDIR:=$(call FullPath,$(OUTPUTDIR)) -# Get shared compiler settings -include $(BUILDDIR)/common/shared/Compiler.gmk diff --git a/corba/make/common/shared/Platform.gmk b/corba/make/common/shared/Platform.gmk index edaf8582fde..e1bb4466531 100644 --- a/corba/make/common/shared/Platform.gmk +++ b/corba/make/common/shared/Platform.gmk @@ -58,19 +58,10 @@ PLATFORM_SHARED=done # ARCH sparc, sparcv9, i586, amd64, or ia64 # ARCH_FAMILY sparc or i586 # ARCHPROP sparc or x86 -# ARCH_VM_SUBDIR jre/bin, jre/lib/sparc, etc. -# LIBARCH sparc, sparcv9, i386, amd64, or ia64 # DEV_NULL destination of /dev/null, NUL or /dev/NULL # CLASSPATH_SEPARATOR separator in classpath, ; or : -# LIB_PREFIX dynamic or static library prefix, lib or empty -# LIB_SUFFIX static library file suffix, .lib or .a? -# LIBRARY_SUFFIX dynamic library file suffix, .dll or .so -# OBJECT_SUFFIX object file suffix, .o or .obj -# EXE_SUFFIX executable file suffix, .exe or empty # BUNDLE_FILE_SUFFIX suffix for bundles: .tar or .tar.gz # ISA_DIR solaris only: /sparcv9 or /amd64 -# LIBARCH32 solaris only: sparc or i386 -# LIBARCH64 solaris only: sparcv9 or amd64 # REQUIRED_WINDOWS_NAME windows only: basic name of windows # REQUIRED_WINDOWS_VERSION windows only: specific version of windows # USING_CYGWIN windows only: true or false @@ -129,7 +120,6 @@ ifeq ($(SYSTEM_UNAME), SunOS) # Need to maintain the jre/lib/i386 location for 32-bit Intel ifeq ($(ARCH), i586) ARCH_FAMILY = $(ARCH) - LIBARCH = i386 # Value of Java os.arch property ARCHPROP = x86 else @@ -138,17 +128,8 @@ ifeq ($(SYSTEM_UNAME), SunOS) else ARCH_FAMILY = sparc endif - LIBARCH = $(ARCH) # Value of Java os.arch property - ARCHPROP = $(LIBARCH) - endif - # The two LIBARCH names - ifeq ($(ARCH_FAMILY), sparc) - LIBARCH32 = sparc - LIBARCH64 = sparcv9 - else - LIBARCH32 = i386 - LIBARCH64 = amd64 + ARCHPROP = $(ARCH) endif # Suffix for file bundles used in previous release BUNDLE_FILE_SUFFIX=.tar @@ -218,16 +199,12 @@ ifeq ($(SYSTEM_UNAME), Linux) endif endif - # Need to maintain the jre/lib/i386 location for 32-bit Intel ifeq ($(ARCH), i586) - LIBARCH = i386 + ARCHPROP = i386 else - LIBARCH = $(ARCH) + ARCHPROP = $(ARCH) endif - # Value of Java os.arch property - ARCHPROP = $(LIBARCH) - # Suffix for file bundles used in previous release BUNDLE_FILE_SUFFIX=.tar.gz # Minimum disk space needed as determined by running 'du -sk' on @@ -303,9 +280,7 @@ ifeq ($(PLATFORM), windows) endif endif export ARCH_DATA_MODEL - # LIBARCH is used to preserve the jre/lib/i386 directory name for 32-bit intel ARCH=i586 - LIBARCH=i386 # Value of Java os.arch property ARCHPROP=x86 REQUIRED_WINDOWS_NAME=Windows Professional 2000 @@ -323,9 +298,8 @@ ifeq ($(PLATFORM), windows) ARCH=ia64 endif endif - LIBARCH=$(ARCH) # Value of Java os.arch property - ARCHPROP=$(LIBARCH) + ARCHPROP=$(ARCH) endif ARCH_FAMILY = $(ARCH) # Where is unwanted output to be delivered? @@ -337,14 +311,6 @@ ifeq ($(PLATFORM), windows) export DEV_NULL # Classpath separator CLASSPATH_SEPARATOR = ; - # The suffix used for object file (.o for unix .obj for windows) - OBJECT_SUFFIX = obj - # The suffix applied to executables (.exe for windows, nothing for solaris) - EXE_SUFFIX = .exe - # The prefix applied to library files (lib for solaris, nothing for windows) - LIB_PREFIX= - LIBRARY_SUFFIX = dll - LIB_SUFFIX = lib # User name determination (set _USER) ifndef USER ifdef USERNAME @@ -359,8 +325,6 @@ ifeq ($(PLATFORM), windows) else _USER:=$(USER) endif - # Location of client/server directories - ARCH_VM_SUBDIR=jre/bin # Suffix for file bundles used in previous release BUNDLE_FILE_SUFFIX=.tar # Minimum disk space needed as determined by running 'du -sk' on @@ -430,16 +394,6 @@ ifneq ($(PLATFORM), windows) export DEV_NULL # Character used between entries in classpath CLASSPATH_SEPARATOR = : - # suffix used for object file (.o for unix .obj for windows) - OBJECT_SUFFIX = o - # The suffix applied to runtime libraries - LIBRARY_SUFFIX = so - # The suffix applied to link libraries - LIB_SUFFIX = so - # The suffix applied to executables (.exe for windows, nothing for solaris) - EXE_SUFFIX = - # The prefix applied to library files (lib for solaris, nothing for windows) - LIB_PREFIX = lib # User name determination (set _USER) ifndef USER ifdef LOGNAME @@ -450,8 +404,6 @@ ifneq ($(PLATFORM), windows) else _USER:=$(USER) endif - # Location of client/server directories - ARCH_VM_SUBDIR=jre/lib/$(LIBARCH) endif # If blanks in the username, use the first 4 words and pack them together diff --git a/corba/make/jprt.properties b/corba/make/jprt.properties index b35f8317a7f..c95c9d06869 100644 --- a/corba/make/jprt.properties +++ b/corba/make/jprt.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,29 +24,13 @@ # # Properties for jprt -jprt.tools.default.release=jdk1.7.0 -# Specific platform list -jprt.build.platforms=\ -solaris_sparc_5.10,\ -solaris_sparcv9_5.10,\ -solaris_i586_5.10,\ -solaris_x64_5.10,\ -linux_i586_2.6,\ -linux_x64_2.6,\ -windows_i586_5.0,\ -windows_x64_5.2 +# Use whatever release that the submitted job requests +jprt.tools.default.release=${jprt.submit.release} -# The different build flavors we want +# The different build flavors we want, we override here so we just get these 2 jprt.build.flavors=product,fastdebug -# Explicitly designate what the 32bit match is for the 64bit build -jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10 -jprt.solaris_sparcv9_5.10.build.platform.match32=solaris_sparc_5.10 -jprt.solaris_x64.build.platform.match32=solaris_i586_5.10 -jprt.solaris_x64_5.10.build.platform.match32=solaris_i586_5.10 - -# Directories needed to build -jprt.bundle.src.dirs=make src -jprt.bundle.exclude.src.dirs=build dist +# Directories to be excluded from the source bundles +jprt.bundle.exclude.src.dirs=build dist webrev diff --git a/corba/make/org/omg/idl/Makefile b/corba/make/org/omg/idl/Makefile index 27a8cfa897f..87ad9db55a9 100644 --- a/corba/make/org/omg/idl/Makefile +++ b/corba/make/org/omg/idl/Makefile @@ -32,12 +32,6 @@ PACKAGE = com.sun.tools.corba.se.idl PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk -# This program must contain a manifest that defines the execution level -# needed to follow standard Vista User Access Control Guidelines -# This must be set before Program.gmk is included -# -BUILD_MANIFEST=true - # # Files # diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 8fc773e9e0a..71539d8e572 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -115,3 +115,9 @@ b4acf10eb134fe930802c97e36db65e7ccb544b5 jdk7-b104 cc3fdfeb54b049f18edcf3463e6ab051d0b7b609 hs19-b05 688a538aa65412178286ae2a6b0c00b6711e121b hs19-b06 bf496cbe9b74dda5975a1559da7ecfdd313e509e jdk7-b107 +0000000000000000000000000000000000000000 hs19-b06 +6c43216df13513a0f96532aa06f213066c49e27b hs19-b06 +e44a93947ccbfce712b51725f313163606f15486 jdk7-b108 +cc4bb3022b3144dc5db0805b9ef6c7eff2aa3b81 jdk7-b109 +2f25f2b8de2700a1822463b1bd3d02b5e218018f jdk7-b110 +07b042e13dde4f3479ba9ec55120fcd5e8623323 jdk7-b111 diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java index 35a4ab22b69..3bbe31378d5 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java @@ -1037,7 +1037,7 @@ public class CommandProcessor { public void prologue(Address start, Address end) { } public void visit(CodeBlob blob) { - fout.println(gen.genHTML(blob.instructionsBegin())); + fout.println(gen.genHTML(blob.contentBegin())); } public void epilogue() { } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/c1/Runtime1.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/c1/Runtime1.java index cbabffa70f5..28f181a53b6 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/c1/Runtime1.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/c1/Runtime1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ public class Runtime1 { /** FIXME: consider making argument "type-safe" in Java port */ public Address entryFor(int id) { - return blobFor(id).instructionsBegin(); + return blobFor(id).codeBegin(); } /** FIXME: consider making argument "type-safe" in Java port */ diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java index be3e853882c..937c5ce9628 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,8 @@ public class CodeBlob extends VMObject { private static CIntegerField sizeField; private static CIntegerField headerSizeField; private static CIntegerField relocationSizeField; - private static CIntegerField instructionsOffsetField; + private static CIntegerField contentOffsetField; + private static CIntegerField codeOffsetField; private static CIntegerField frameCompleteOffsetField; private static CIntegerField dataOffsetField; private static CIntegerField frameSizeField; @@ -68,7 +69,8 @@ public class CodeBlob extends VMObject { headerSizeField = type.getCIntegerField("_header_size"); relocationSizeField = type.getCIntegerField("_relocation_size"); frameCompleteOffsetField = type.getCIntegerField("_frame_complete_offset"); - instructionsOffsetField = type.getCIntegerField("_instructions_offset"); + contentOffsetField = type.getCIntegerField("_content_offset"); + codeOffsetField = type.getCIntegerField("_code_offset"); dataOffsetField = type.getCIntegerField("_data_offset"); frameSizeField = type.getCIntegerField("_frame_size"); oopMapsField = type.getAddressField("_oop_maps"); @@ -111,11 +113,19 @@ public class CodeBlob extends VMObject { // public RelocInfo relocationBegin(); // public RelocInfo relocationEnd(); - public Address instructionsBegin() { - return headerBegin().addOffsetTo(instructionsOffsetField.getValue(addr)); + public Address contentBegin() { + return headerBegin().addOffsetTo(contentOffsetField.getValue(addr)); } - public Address instructionsEnd() { + public Address contentEnd() { + return headerBegin().addOffsetTo(dataOffsetField.getValue(addr)); + } + + public Address codeBegin() { + return headerBegin().addOffsetTo(contentOffsetField.getValue(addr)); + } + + public Address codeEnd() { return headerBegin().addOffsetTo(dataOffsetField.getValue(addr)); } @@ -128,24 +138,27 @@ public class CodeBlob extends VMObject { } // Offsets - public int getRelocationOffset() { return (int) headerSizeField.getValue(addr); } - public int getInstructionsOffset() { return (int) instructionsOffsetField.getValue(addr); } - public int getDataOffset() { return (int) dataOffsetField.getValue(addr); } + public int getRelocationOffset() { return (int) headerSizeField .getValue(addr); } + public int getContentOffset() { return (int) contentOffsetField.getValue(addr); } + public int getCodeOffset() { return (int) codeOffsetField .getValue(addr); } + public int getDataOffset() { return (int) dataOffsetField .getValue(addr); } // Sizes - public int getSize() { return (int) sizeField.getValue(addr); } - public int getHeaderSize() { return (int) headerSizeField.getValue(addr); } + public int getSize() { return (int) sizeField .getValue(addr); } + public int getHeaderSize() { return (int) headerSizeField.getValue(addr); } // FIXME: add getRelocationSize() - public int getInstructionsSize() { return (int) instructionsEnd().minus(instructionsBegin()); } - public int getDataSize() { return (int) dataEnd().minus(dataBegin()); } + public int getContentSize() { return (int) contentEnd().minus(contentBegin()); } + public int getCodeSize() { return (int) codeEnd() .minus(codeBegin()); } + public int getDataSize() { return (int) dataEnd() .minus(dataBegin()); } // Containment - public boolean blobContains(Address addr) { return headerBegin().lessThanOrEqual(addr) && dataEnd().greaterThan(addr); } + public boolean blobContains(Address addr) { return headerBegin() .lessThanOrEqual(addr) && dataEnd() .greaterThan(addr); } // FIXME: add relocationContains - public boolean instructionsContains(Address addr) { return instructionsBegin().lessThanOrEqual(addr) && instructionsEnd().greaterThan(addr); } - public boolean dataContains(Address addr) { return dataBegin().lessThanOrEqual(addr) && dataEnd().greaterThan(addr); } - public boolean contains(Address addr) { return instructionsContains(addr); } - public boolean isFrameCompleteAt(Address a) { return instructionsContains(a) && a.minus(instructionsBegin()) >= frameCompleteOffsetField.getValue(addr); } + public boolean contentContains(Address addr) { return contentBegin().lessThanOrEqual(addr) && contentEnd().greaterThan(addr); } + public boolean codeContains(Address addr) { return codeBegin() .lessThanOrEqual(addr) && codeEnd() .greaterThan(addr); } + public boolean dataContains(Address addr) { return dataBegin() .lessThanOrEqual(addr) && dataEnd() .greaterThan(addr); } + public boolean contains(Address addr) { return contentContains(addr); } + public boolean isFrameCompleteAt(Address a) { return codeContains(a) && a.minus(codeBegin()) >= frameCompleteOffsetField.getValue(addr); } // Reclamation support (really only used by the nmethods, but in order to get asserts to work // in the CodeCache they are defined virtual here) @@ -168,7 +181,7 @@ public class CodeBlob extends VMObject { if (Assert.ASSERTS_ENABLED) { Assert.that(getOopMaps() != null, "nope"); } - return getOopMaps().findMapAtOffset(pc.minus(instructionsBegin()), debugging); + return getOopMaps().findMapAtOffset(pc.minus(codeBegin()), debugging); } // virtual void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, void f(oop*)) { ShouldNotReachHere(); } @@ -200,7 +213,8 @@ public class CodeBlob extends VMObject { } protected void printComponentsOn(PrintStream tty) { - tty.println(" instructions: [" + instructionsBegin() + ", " + instructionsEnd() + "), " + + tty.println(" content: [" + contentBegin() + ", " + contentEnd() + "), " + + " code: [" + codeBegin() + ", " + codeEnd() + "), " + " data: [" + dataBegin() + ", " + dataEnd() + "), " + " frame size: " + getFrameSize()); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java index a6641dd166a..80da843d3ab 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -134,10 +134,10 @@ public class NMethod extends CodeBlob { public boolean isOSRMethod() { return getEntryBCI() != VM.getVM().getInvocationEntryBCI(); } /** Boundaries for different parts */ - public Address constantsBegin() { return instructionsBegin(); } + public Address constantsBegin() { return contentBegin(); } public Address constantsEnd() { return getEntryPoint(); } - public Address codeBegin() { return getEntryPoint(); } - public Address codeEnd() { return headerBegin().addOffsetTo(getStubOffset()); } + public Address instsBegin() { return codeBegin(); } + public Address instsEnd() { return headerBegin().addOffsetTo(getStubOffset()); } public Address exceptionBegin() { return headerBegin().addOffsetTo(getExceptionOffset()); } public Address deoptBegin() { return headerBegin().addOffsetTo(getDeoptOffset()); } public Address stubBegin() { return headerBegin().addOffsetTo(getStubOffset()); } @@ -156,7 +156,7 @@ public class NMethod extends CodeBlob { public Address nulChkTableEnd() { return headerBegin().addOffsetTo(getNMethodEndOffset()); } public int constantsSize() { return (int) constantsEnd() .minus(constantsBegin()); } - public int codeSize() { return (int) codeEnd() .minus(codeBegin()); } + public int instsSize() { return (int) instsEnd() .minus(instsBegin()); } public int stubSize() { return (int) stubEnd() .minus(stubBegin()); } public int oopsSize() { return (int) oopsEnd() .minus(oopsBegin()); } public int scopesDataSize() { return (int) scopesDataEnd() .minus(scopesDataBegin()); } @@ -169,7 +169,7 @@ public class NMethod extends CodeBlob { public int totalSize() { return constantsSize() + - codeSize() + + instsSize() + stubSize() + scopesDataSize() + scopesPCsSize() + @@ -179,7 +179,7 @@ public class NMethod extends CodeBlob { } public boolean constantsContains (Address addr) { return constantsBegin() .lessThanOrEqual(addr) && constantsEnd() .greaterThan(addr); } - public boolean codeContains (Address addr) { return codeBegin() .lessThanOrEqual(addr) && codeEnd() .greaterThan(addr); } + public boolean instsContains (Address addr) { return instsBegin() .lessThanOrEqual(addr) && instsEnd() .greaterThan(addr); } public boolean stubContains (Address addr) { return stubBegin() .lessThanOrEqual(addr) && stubEnd() .greaterThan(addr); } public boolean oopsContains (Address addr) { return oopsBegin() .lessThanOrEqual(addr) && oopsEnd() .greaterThan(addr); } public boolean scopesDataContains (Address addr) { return scopesDataBegin() .lessThanOrEqual(addr) && scopesDataEnd() .greaterThan(addr); } @@ -353,7 +353,8 @@ public class NMethod extends CodeBlob { protected void printComponentsOn(PrintStream tty) { // FIXME: add relocation information - tty.println(" instructions: [" + instructionsBegin() + ", " + instructionsEnd() + "), " + + tty.println(" content: [" + contentBegin() + ", " + contentEnd() + "), " + + " code: [" + codeBegin() + ", " + codeEnd() + "), " + " data: [" + dataBegin() + ", " + dataEnd() + "), " + " oops: [" + oopsBegin() + ", " + oopsEnd() + "), " + " frame size: " + getFrameSize()); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java index ff4b9480714..c6bf5d78b5e 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,7 @@ public class PCDesc extends VMObject { } public Address getRealPC(NMethod code) { - return code.instructionsBegin().addOffsetTo(getPCOffset()); + return code.codeBegin().addOffsetTo(getPCOffset()); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindInCodeCachePanel.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindInCodeCachePanel.java index 96e7d8ac61f..21619b1f5ae 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindInCodeCachePanel.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindInCodeCachePanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -190,11 +190,11 @@ public class FindInCodeCachePanel extends SAPanel { private void reportResult(StringBuffer result, CodeBlob blob) { result.append(""); result.append(blob.getName()); result.append("@"); - result.append(blob.instructionsBegin()); + result.append(blob.contentBegin()); result.append("
"); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java index d594404f414..e70ba946110 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java @@ -1415,13 +1415,13 @@ public class HTMLGenerator implements /* imports */ ClassConstants { buf.append(genMethodAndKlassLink(nmethod.getMethod())); buf.h3("Compiled Code"); - sun.jvm.hotspot.debugger.Address codeBegin = nmethod.codeBegin(); - sun.jvm.hotspot.debugger.Address codeEnd = nmethod.codeEnd(); - final int codeSize = (int)codeEnd.minus(codeBegin); - final long startPc = addressToLong(codeBegin); - final byte[] code = new byte[codeSize]; + sun.jvm.hotspot.debugger.Address instsBegin = nmethod.instsBegin(); + sun.jvm.hotspot.debugger.Address instsEnd = nmethod.instsEnd(); + final int instsSize = nmethod.instsSize(); + final long startPc = addressToLong(instsBegin); + final byte[] code = new byte[instsSize]; for (int i=0; i < code.length; i++) - code[i] = codeBegin.getJByteAt(i); + code[i] = instsBegin.getJByteAt(i); final long verifiedEntryPoint = addressToLong(nmethod.getVerifiedEntryPoint()); final long entryPoint = addressToLong(nmethod.getEntryPoint()); @@ -1499,8 +1499,8 @@ public class HTMLGenerator implements /* imports */ ClassConstants { buf.h3("CodeBlob"); buf.h3("Compiled Code"); - final sun.jvm.hotspot.debugger.Address codeBegin = blob.instructionsBegin(); - final int codeSize = blob.getInstructionsSize(); + final sun.jvm.hotspot.debugger.Address codeBegin = blob.codeBegin(); + final int codeSize = blob.getCodeSize(); final long startPc = addressToLong(codeBegin); final byte[] code = new byte[codeSize]; for (int i=0; i < code.length; i++) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java index b1e3c4acc9a..379e83e83f8 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java @@ -96,15 +96,15 @@ public class PointerFinder { if (Assert.ASSERTS_ENABLED) { Assert.that(loc.blob != null, "Should have found CodeBlob"); } - loc.inBlobInstructions = loc.blob.instructionsContains(a); - loc.inBlobData = loc.blob.dataContains(a); + loc.inBlobCode = loc.blob.codeContains(a); + loc.inBlobData = loc.blob.dataContains(a); if (loc.blob.isNMethod()) { NMethod nm = (NMethod) loc.blob; loc.inBlobOops = nm.oopsContains(a); } - loc.inBlobUnknownLocation = (!(loc.inBlobInstructions || + loc.inBlobUnknownLocation = (!(loc.inBlobCode || loc.inBlobData || loc.inBlobOops)); return loc; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java index fd54b0d45db..85559d4371f 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ public class PointerLocation { InterpreterCodelet interpreterCodelet; CodeBlob blob; // FIXME: add more detail about CodeBlob - boolean inBlobInstructions; + boolean inBlobCode; boolean inBlobData; boolean inBlobOops; boolean inBlobUnknownLocation; @@ -142,8 +142,8 @@ public class PointerLocation { return blob; } - public boolean isInBlobInstructions() { - return inBlobInstructions; + public boolean isInBlobCode() { + return inBlobCode; } public boolean isInBlobData() { @@ -233,8 +233,8 @@ public class PointerLocation { } else if (isInCodeCache()) { CodeBlob b = getCodeBlob(); tty.print("In "); - if (isInBlobInstructions()) { - tty.print("instructions"); + if (isInBlobCode()) { + tty.print("code"); } else if (isInBlobData()) { tty.print("data"); } else if (isInBlobOops()) { diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index dae71d920fb..dfc53081cb3 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -33,9 +33,9 @@ # Don't put quotes (fail windows build). HOTSPOT_VM_COPYRIGHT=Copyright 2010 -HS_MAJOR_VER=19 +HS_MAJOR_VER=20 HS_MINOR_VER=0 -HS_BUILD_NUMBER=06 +HS_BUILD_NUMBER=01 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff --git a/hotspot/make/jprt.properties b/hotspot/make/jprt.properties index 507c98f3cf6..04554aabe92 100644 --- a/hotspot/make/jprt.properties +++ b/hotspot/make/jprt.properties @@ -47,6 +47,8 @@ jprt.sync.push=false # Define the Solaris platforms we want for the various releases jprt.my.solaris.sparc.jdk7=solaris_sparc_5.10 +jprt.my.solaris.sparc.jdk7b107=solaris_sparc_5.10 +jprt.my.solaris.sparc.jdk7temp=solaris_sparc_5.10 jprt.my.solaris.sparc.jdk6=solaris_sparc_5.8 jprt.my.solaris.sparc.jdk6perf=solaris_sparc_5.8 jprt.my.solaris.sparc.jdk6u10=solaris_sparc_5.8 @@ -56,6 +58,8 @@ jprt.my.solaris.sparc.jdk6u20=solaris_sparc_5.8 jprt.my.solaris.sparc=${jprt.my.solaris.sparc.${jprt.tools.default.release}} jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10 +jprt.my.solaris.sparcv9.jdk7b107=solaris_sparcv9_5.10 +jprt.my.solaris.sparcv9.jdk7temp=solaris_sparcv9_5.10 jprt.my.solaris.sparcv9.jdk6=solaris_sparcv9_5.8 jprt.my.solaris.sparcv9.jdk6perf=solaris_sparcv9_5.8 jprt.my.solaris.sparcv9.jdk6u10=solaris_sparcv9_5.8 @@ -65,6 +69,8 @@ jprt.my.solaris.sparcv9.jdk6u20=solaris_sparcv9_5.8 jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}} jprt.my.solaris.i586.jdk7=solaris_i586_5.10 +jprt.my.solaris.i586.jdk7b107=solaris_i586_5.10 +jprt.my.solaris.i586.jdk7temp=solaris_i586_5.10 jprt.my.solaris.i586.jdk6=solaris_i586_5.8 jprt.my.solaris.i586.jdk6perf=solaris_i586_5.8 jprt.my.solaris.i586.jdk6u10=solaris_i586_5.8 @@ -74,6 +80,8 @@ jprt.my.solaris.i586.jdk6u20=solaris_i586_5.8 jprt.my.solaris.i586=${jprt.my.solaris.i586.${jprt.tools.default.release}} jprt.my.solaris.x64.jdk7=solaris_x64_5.10 +jprt.my.solaris.x64.jdk7b107=solaris_x64_5.10 +jprt.my.solaris.x64.jdk7temp=solaris_x64_5.10 jprt.my.solaris.x64.jdk6=solaris_x64_5.10 jprt.my.solaris.x64.jdk6perf=solaris_x64_5.10 jprt.my.solaris.x64.jdk6u10=solaris_x64_5.10 @@ -83,6 +91,8 @@ jprt.my.solaris.x64.jdk6u20=solaris_x64_5.10 jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}} jprt.my.linux.i586.jdk7=linux_i586_2.6 +jprt.my.linux.i586.jdk7b107=linux_i586_2.6 +jprt.my.linux.i586.jdk7temp=linux_i586_2.6 jprt.my.linux.i586.jdk6=linux_i586_2.4 jprt.my.linux.i586.jdk6perf=linux_i586_2.4 jprt.my.linux.i586.jdk6u10=linux_i586_2.4 @@ -92,6 +102,8 @@ jprt.my.linux.i586.jdk6u20=linux_i586_2.4 jprt.my.linux.i586=${jprt.my.linux.i586.${jprt.tools.default.release}} jprt.my.linux.x64.jdk7=linux_x64_2.6 +jprt.my.linux.x64.jdk7b107=linux_x64_2.6 +jprt.my.linux.x64.jdk7temp=linux_x64_2.6 jprt.my.linux.x64.jdk6=linux_x64_2.4 jprt.my.linux.x64.jdk6perf=linux_x64_2.4 jprt.my.linux.x64.jdk6u10=linux_x64_2.4 @@ -100,7 +112,9 @@ jprt.my.linux.x64.jdk6u18=linux_x64_2.4 jprt.my.linux.x64.jdk6u20=linux_x64_2.4 jprt.my.linux.x64=${jprt.my.linux.x64.${jprt.tools.default.release}} -jprt.my.windows.i586.jdk7=windows_i586_5.0 +jprt.my.windows.i586.jdk7=windows_i586_5.1 +jprt.my.windows.i586.jdk7b107=windows_i586_5.0 +jprt.my.windows.i586.jdk7temp=windows_i586_5.0 jprt.my.windows.i586.jdk6=windows_i586_5.0 jprt.my.windows.i586.jdk6perf=windows_i586_5.0 jprt.my.windows.i586.jdk6u10=windows_i586_5.0 @@ -110,6 +124,8 @@ jprt.my.windows.i586.jdk6u20=windows_i586_5.0 jprt.my.windows.i586=${jprt.my.windows.i586.${jprt.tools.default.release}} jprt.my.windows.x64.jdk7=windows_x64_5.2 +jprt.my.windows.x64.jdk7b107=windows_x64_5.2 +jprt.my.windows.x64.jdk7temp=windows_x64_5.2 jprt.my.windows.x64.jdk6=windows_x64_5.2 jprt.my.windows.x64.jdk6perf=windows_x64_5.2 jprt.my.windows.x64.jdk6u10=windows_x64_5.2 diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index e671c4bf94a..3187fb914b8 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # # This makefile creates a build tree and lights off a build. @@ -45,13 +45,13 @@ # # make REMOTE="rsh -l me myotherlinuxbox" -# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding. -# JDI binding on SA produces two binaries: +# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding. +# JDI binding on SA produces two binaries: # 1. sa-jdi.jar - This is build before building libjvm[_g].so # Please refer to ./makefiles/sa.make # 2. libsa[_g].so - Native library for SA - This is built after # libjsig[_g].so (signal interposition library) -# Please refer to ./makefiles/vm.make +# Please refer to ./makefiles/vm.make # If $(GAMMADIR)/agent dir is not present, SA components are not built. ifeq ($(GAMMADIR),) @@ -61,11 +61,9 @@ include $(GAMMADIR)/make/defs.make endif include $(GAMMADIR)/make/$(OSNAME)/makefiles/rules.make -ifndef LP64 ifndef CC_INTERP FORCE_TIERED=1 endif -endif ifdef LP64 ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","") diff --git a/hotspot/make/linux/makefiles/sa.make b/hotspot/make/linux/makefiles/sa.make index 19d68083ede..a58a3c20df1 100644 --- a/hotspot/make/linux/makefiles/sa.make +++ b/hotspot/make/linux/makefiles/sa.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,9 @@ MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules AGENT_FILES1 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES1)) AGENT_FILES2 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES2)) +AGENT_FILES1_LIST := $(GENERATED)/agent1.classes.list +AGENT_FILES2_LIST := $(GENERATED)/agent2.classes.list + SA_CLASSDIR = $(GENERATED)/saclasses SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION)" @@ -79,10 +82,24 @@ $(GENERATED)/sa-jdi.jar: $(AGENT_FILES1) $(AGENT_FILES2) $(QUIETLY) if [ ! -d $(SA_CLASSDIR) ] ; then \ mkdir -p $(SA_CLASSDIR); \ fi - - $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES1) - $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES2) - + +# Note: When indented, make tries to execute the '$(shell' comment. +# In some environments, cmd processors have limited line length. +# To prevent the javac invocation in the next block from using +# a very long cmd line, we use javac's @file-list option. We +# generate the file lists using make's built-in 'foreach' control +# flow which also avoids cmd processor line length issues. Since +# the 'foreach' is done as part of make's macro expansion phase, +# the initialization of the lists is also done in the same phase +# using '$(shell rm ...' instead of using the more traditional +# 'rm ...' rule. + $(shell rm -rf $(AGENT_FILES1_LIST) $(AGENT_FILES2_LIST)) + $(foreach file,$(AGENT_FILES1),$(shell echo $(file) >> $(AGENT_FILES1_LIST))) + $(foreach file,$(AGENT_FILES2),$(shell echo $(file) >> $(AGENT_FILES2_LIST))) + + $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST) + $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST) + $(QUIETLY) $(REMOTE) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js @@ -101,3 +118,4 @@ $(GENERATED)/sa-jdi.jar: $(AGENT_FILES1) $(AGENT_FILES2) clean: rm -rf $(SA_CLASSDIR) rm -rf $(GENERATED)/sa-jdi.jar + rm -rf $(AGENT_FILES1_LIST) $(AGENT_FILES2_LIST) diff --git a/hotspot/make/solaris/Makefile b/hotspot/make/solaris/Makefile index 08063e0f9da..622ddd1f884 100644 --- a/hotspot/make/solaris/Makefile +++ b/hotspot/make/solaris/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # # This makefile creates a build tree and lights off a build. @@ -36,13 +36,13 @@ # or BOOTDIR has to be set. We do *not* search javac, javah, rmic etc. # from the PATH. -# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding. -# JDI binding on SA produces two binaries: +# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding. +# JDI binding on SA produces two binaries: # 1. sa-jdi.jar - This is build before building libjvm[_g].so # Please refer to ./makefiles/sa.make # 2. libsaproc[_g].so - Native library for SA - This is built after # libjsig[_g].so (signal interposition library) -# Please refer to ./makefiles/vm.make +# Please refer to ./makefiles/vm.make # If $(GAMMADIR)/agent dir is not present, SA components are not built. ifeq ($(GAMMADIR),) @@ -52,11 +52,9 @@ include $(GAMMADIR)/make/defs.make endif include $(GAMMADIR)/make/$(OSNAME)/makefiles/rules.make -ifndef LP64 ifndef CC_INTERP FORCE_TIERED=1 endif -endif ifdef LP64 ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","") diff --git a/hotspot/make/solaris/makefiles/dtrace.make b/hotspot/make/solaris/makefiles/dtrace.make index 39ae1e46be1..2338c01099d 100644 --- a/hotspot/make/solaris/makefiles/dtrace.make +++ b/hotspot/make/solaris/makefiles/dtrace.make @@ -165,7 +165,7 @@ $(DTRACE).d: $(DTRACE_SRCDIR)/hotspot.d $(DTRACE_SRCDIR)/hotspot_jni.d \ $(DTRACE.o): $(DTRACE).d $(JVMOFFS).h $(JVMOFFS)Index.h $(DTraced_Files) @echo Compiling $(DTRACE).d - $(QUIETLY) $(DTRACE_PROG) $(DTRACE_OPTS) -C -I. -G -o $@ -s $(DTRACE).d \ + $(QUIETLY) $(DTRACE_PROG) $(DTRACE_OPTS) -C -I. -G -xlazyload -o $@ -s $(DTRACE).d \ $(DTraced_Files) ||\ STATUS=$$?;\ if [ x"$$STATUS" = x"1" -a \ diff --git a/hotspot/make/solaris/makefiles/reorder_TIERED_sparcv9 b/hotspot/make/solaris/makefiles/reorder_TIERED_sparcv9 new file mode 100644 index 00000000000..15c03b78514 --- /dev/null +++ b/hotspot/make/solaris/makefiles/reorder_TIERED_sparcv9 @@ -0,0 +1,4477 @@ +data = R0x2000; +text = LOAD ?RXO; + + +text: .text%__1cCosOjavaTimeMillis6F_x_; +text: .text%__1cQIndexSetIteratorQadvance_and_next6M_I_; +text: .text%__1cNinstanceKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cNinstanceKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cNinstanceKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cOtypeArrayKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cOtypeArrayKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cIPhaseIFGIadd_edge6MII_i_; +text: .text%__1cQIndexSetIterator2t6MpnIIndexSet__v_; +text: .text%__1cENodeEjvms6kM_pnIJVMState__; +text: .text%__1cIIndexSetWalloc_block_containing6MI_pn0AIBitBlock__; +text: .text%__1cETypeDcmp6Fkpk03_i_; +text: .text%__1cENodeHlatency6MI_I_; +text: .text%__1cHRegMaskJis_bound16kM_i_; +text: .text%__1cDff16FI_i_; +text: .text%__1cHRegMaskESize6kM_I_; +text: .text%__1cXresource_allocate_bytes6FI_pc_; +text: .text%__1cENodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJVectorSet2R6MI_rnDSet__; +text: .text%__1cHRegMaskJis_bound26kM_i_; +text: .text%__1cNSharedRuntimeElmul6Fxx_x_; +text: .text%__1cIMachNodeGOpcode6kM_i_; +text: .text%__1cJiRegIOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cIIndexSetKinitialize6MI_v_; +text: .text%__1cITypeNodeLbottom_type6kM_pknEType__; +text: .text%__1cPClassFileStreamGget_u26MpnGThread__H_; +text: .text%__1cKTypeOopPtrFklass6kM_pnHciKlass__: type.o; +text: .text%__1cETypeFuhash6Fkpk0_i_; +text: .text%__1cQIndexSetIteratorEnext6M_I_: chaitin.o; +text: .text%__1cENodeIout_grow6MI_v_; +text: .text%__1cOloadConI13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cNobjArrayKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cENodeHadd_req6Mp0_v_; +text: .text%__1cJMarkSweepUAdjustPointerClosureGdo_oop6MppnHoopDesc__v_: markSweep.o; +text: .text%__1cNobjArrayKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cNobjArrayKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cOloadConI13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cICallNodeKmatch_edge6kMI_I_; +text: .text%__1cINodeHashQhash_find_insert6MpnENode__2_; +text: .text%__1cHPhiNodeGOpcode6kM_i_; +text: .text%__1cKbranchNodeNis_block_proj6kM_pknENode__: ad_sparc_misc.o; +text: .text%__1cIProjNodeGOpcode6kM_i_; +text: .text%__1cETypeIhashcons6M_pk0_; +text: .text%__1cOPhaseIdealLoopUbuild_loop_late_post6MpnENode_pk0_v_; +text: .text%__1cMPhaseChaitinTinterfere_with_live6MIpnIIndexSet__v_; +text: .text%__1cWNode_Backward_IteratorEnext6M_pnENode__; +text: .text%__1cNIdealLoopTreeJis_member6kMpk0_i_; +text: .text%__1cMMachCallNodeKin_RegMask6kMI_rknHRegMask__; +text: .text%__1cHCompileNnode_bundling6MpknENode__pnGBundle__; +text: .text%__1cGIfNodeGOpcode6kM_i_; +text: .text%__1cOPhaseIdealLoopYsplit_if_with_blocks_pre6MpnENode__2_; +text: .text%__1cOPhaseIdealLoopZsplit_if_with_blocks_post6MpnENode__v_; +text: .text%__1cIUniverseMnon_oop_word6F_pv_; +text: .text%__1cDLRGOcompute_degree6kMr0_i_; +text: .text%__1cFArenaIArealloc6MpvII_1_; +text: .text%__1cIConINodeGOpcode6kM_i_; +text: .text%__1cETypeEmeet6kMpk0_2_; +text: .text%__1cENode2t6MI_v_; +text: .text%__1cRMachSpillCopyNodeJideal_reg6kM_I_: ad_sparc.o; +text: .text%__1cIPipelineXfunctional_unit_latency6kMIpk0_I_; +text: .text%__1cWPSScavengeRootsClosureGdo_oop6MppnHoopDesc__v_: psTasks.o; +text: .text%__1cLsymbolKlassIoop_size6kMpnHoopDesc__i_; +text: .text%__1cJCProjNodeNis_block_proj6kM_pknENode__: cfgnode.o; +text: .text%__1cKIfTrueNodeGOpcode6kM_i_; +text: .text%__1cNRelocIteratorTadvance_over_prefix6M_v_; +text: .text%__1cIMachNodeKin_RegMask6kMI_rknHRegMask__; +text: .text%__1cJloadPNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cIPhaseIFGQeffective_degree6kMI_i_; +text: .text%__1cWConstantPoolCacheEntryPfollow_contents6M_v_; +text: .text%__1cWConstantPoolCacheEntryPadjust_pointers6M_v_; +text: .text%__1cIAddPNodeGOpcode6kM_i_; +text: .text%__1cIPhaseIFGJre_insert6MI_v_; +text: .text%__1cIPhaseIFGLremove_node6MI_pnIIndexSet__; +text: .text%__1cKNode_ArrayGinsert6MIpnENode__v_; +text: .text%__1cHTypeIntEhash6kM_i_; +text: .text%__1cLsymbolKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cLsymbolKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cMPhaseIterGVNNtransform_old6MpnENode__2_; +text: .text%__1cDfh16FI_i_; +text: .text%__1cNMachIdealNodeErule6kM_I_: ad_sparc.o; +text: .text%__1cIIndexSetKfree_block6MI_v_; +text: .text%__1cWShouldNotReachHereNodeNis_block_proj6kM_pknENode__: ad_sparc_misc.o; +text: .text%__1cLIfFalseNodeGOpcode6kM_i_; +text: .text%__1cSCallStaticJavaNodeGOpcode6kM_i_; +text: .text%__1cENodeEhash6kM_I_; +text: .text%__1cOPhaseIdealLoopEsort6MpnNIdealLoopTree_2_2_; +text: .text%__1cMMachProjNodeLbottom_type6kM_pknEType__; +text: .text%JVM_ArrayCopy; +text: .text%__1cOtypeArrayKlassKcopy_array6MpnMarrayOopDesc_i2iipnGThread__v_; +text: .text%__1cNSharedRuntimeDl2f6Fx_f_; +text: .text%__1cPjava_lang_ClassLas_klassOop6FpnHoopDesc__pnMklassOopDesc__; +text: .text%__1cHConNodeGOpcode6kM_i_; +text: .text%__1cMPhaseIterGVNWadd_users_to_worklist06MpnENode__v_; +text: .text%__1cMMachProjNodeGOpcode6kM_i_; +text: .text%__1cJiRegPOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cXPipeline_Use_Cycle_Mask2L6Mi_r0_: ad_sparc_pipeline.o; +text: .text%__1cIBoolNodeGOpcode6kM_i_; +text: .text%__1cYCallStaticJavaDirectNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cENodeEgrow6MI_v_; +text: .text%__1cIciObjectEhash6M_i_; +text: .text%__1cKRegionNodeGOpcode6kM_i_; +text: .text%__1cOPhaseIdealLoopUbuild_loop_tree_impl6MpnENode_i_i_; +text: .text%__1cJMarkSweepSMarkAndPushClosureGdo_oop6MppnHoopDesc__v_: markSweep.o; +text: .text%__1cRMachSpillCopyNodeLbottom_type6kM_pknEType__: ad_sparc.o; +text: .text%__1cOPhaseIdealLoopOget_early_ctrl6MpnENode__2_; +text: .text%__1cIIndexSetKinitialize6MIpnFArena__v_; +text: .text%__1cLmethodKlassIoop_size6kMpnHoopDesc__i_; +text: .text%__1cIPhaseGVNJtransform6MpnENode__2_; +text: .text%__1cOoop_RelocationLunpack_data6M_v_; +text: .text%__1cRmethodDataOopDescHdata_at6Mi_pnLProfileData__; +text: .text%__1cPJavaFrameAnchorNmake_walkable6MpnKJavaThread__v_; +text: .text%__1cENodeNis_block_proj6kM_pk0_; +text: .text%__1cNRelocIteratorFreloc6M_pnKRelocation__; +text: .text%__1cIProjNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cQconstMethodKlassIoop_size6kMpnHoopDesc__i_; +text: .text%__1cPClassFileStreamGget_u16MpnGThread__C_; +text: .text%__1cLTypeInstPtrEhash6kM_i_; +text: .text%__1cYCallStaticJavaDirectNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOPhaseIdealLoopThas_local_phi_input6MpnENode__2_; +text: .text%__1cJloadINodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRMachSpillCopyNodeLout_RegMask6kM_rknHRegMask__: ad_sparc.o; +text: .text%__1cKbranchNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMMachProjNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cMMachProjNodeLout_RegMask6kM_rknHRegMask__: classes.o; +text: .text%__1cRMachSpillCopyNodeKin_RegMask6kMI_rknHRegMask__: ad_sparc.o; +text: .text%__1cbAfinal_graph_reshaping_impl6FpnENode_rnUFinal_Reshape_Counts__v_: compile.o; +text: .text%__1cOtypeArrayKlassIallocate6MipnGThread__pnQtypeArrayOopDesc__; +text: .text%__1cUParallelScavengeHeapVlarge_typearray_limit6M_I_: parallelScavengeHeap.o; +text: .text%__1cIPhaseCCPOtransform_once6MpnENode__2_; +text: .text%__1cGciTypeEmake6FnJBasicType__p0_; +text: .text%__1cKoopFactoryNnew_typeArray6FnJBasicType_ipnGThread__pnQtypeArrayOopDesc__; +text: .text%__1cENodeFclone6kM_p0_; +text: .text%__1cITypeNodeEhash6kM_I_; +text: .text%__1cMPipeline_UseMfull_latency6kMIrk0_I_; +text: .text%__1cRMachSpillCopyNodePoper_input_base6kM_I_: ad_sparc.o; +text: .text%__1cENodeKmatch_edge6kMI_I_; +text: .text%__1cQconstMethodKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cLmethodKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cLmethodKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cQconstMethodKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cOPhaseIdealLoopZremix_address_expressions6MpnENode__2_; +text: .text%__1cSInterpreterRuntimeInewarray6FpnKJavaThread_nJBasicType_i_v_; +text: .text%__1cICallNodeLbottom_type6kM_pknEType__; +text: .text%__1cOPhaseIdealLoopNget_late_ctrl6MpnENode_2_2_; +text: .text%JVM_CurrentTimeMillis; +text: .text%__1cENodeIIdentity6MpnOPhaseTransform__p0_; +text: .text%__1cIPipelinePoperand_latency6kMIpk0_I_; +text: .text%__1cKTypeAryPtrEhash6kM_i_; +text: .text%__1cETypeFxmeet6kMpk0_2_; +text: .text%__1cILRG_ListGextend6MII_v_; +text: .text%__1cJVectorSet2F6kMI_i_; +text: .text%__1cENodeQIdeal_DU_postCCP6MpnIPhaseCCP__p0_; +text: .text%__1cOtypeArrayKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cIProjNodeEhash6kM_I_; +text: .text%__1cIAddINodeGOpcode6kM_i_; +text: .text%__1cIIndexSet2t6Mp0_v_; +text: .text%__1cRmethodDataOopDescJnext_data6MpnLProfileData__2_; +text: .text%__1cITypeNodeJideal_reg6kM_I_; +text: .text%__1cYCallStaticJavaDirectNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cMloadConPNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cHPhiNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cENodeHsize_of6kM_I_; +text: .text%__1cICmpPNodeGOpcode6kM_i_; +text: .text%__1cKNode_ArrayGremove6MI_v_; +text: .text%__1cHPhiNodeEhash6kM_I_; +text: .text%__1cLSymbolTableGlookup6FpkcipnGThread__pnNsymbolOopDesc__; +text: .text%__1cKoopFactoryKnew_symbol6FpkcipnGThread__pnNsymbolOopDesc__; +text: .text%__1cKmethodOperJnum_edges6kM_I_: ad_sparc.o; +text: .text%__1cJStartNodeLbottom_type6kM_pknEType__; +text: .text%__1cHTypeIntFxmeet6kMpknEType__3_; +text: .text%__1cIProjNodeLbottom_type6kM_pknEType__; +text: .text%__1cPciObjectFactoryDget6MpnHoopDesc__pnIciObject__; +text: .text%__1cILocationIwrite_on6MpnUDebugInfoWriteStream__v_; +text: .text%__1cICmpINodeGOpcode6kM_i_; +text: .text%Unsafe_CompareAndSwapLong; +text: .text%__1cNCatchProjNodeGOpcode6kM_i_; +text: .text%__1cQUnique_Node_ListGremove6MpnENode__v_; +text: .text%__1cENode2t6Mp0_v_; +text: .text%__1cNLocationValueIwrite_on6MpnUDebugInfoWriteStream__v_; +text: .text%__1cFframeVinterpreter_frame_bcp6kM_pC_; +text: .text%__1cTCreateExceptionNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cPClassFileStreamHskip_u16MipnGThread__v_; +text: .text%__1cHRegMaskMSmearToPairs6M_v_; +text: .text%__1cMPhaseIterGVNVadd_users_to_worklist6MpnENode__v_; +text: .text%__1cMloadConPNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cNinstanceKlassLfind_method6FpnPobjArrayOopDesc_pnNsymbolOopDesc_4_pnNmethodOopDesc__; +text: .text%__1cMPipeline_UseJadd_usage6Mrk0_v_; +text: .text%__1cIAddPNodeKmatch_edge6kMI_I_; +text: .text%__1cJiRegIOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cGIfNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cGcmpkey6Fpkv1_i_; +text: .text%__1cMMergeMemNodeGOpcode6kM_i_; +text: .text%__1cFframeYinterpreter_frame_method6kM_pnNmethodOopDesc__; +text: .text%__1cIParmNodeGOpcode6kM_i_; +text: .text%__1cPClassFileParserRverify_legal_utf86MpkCipnGThread__v_; +text: .text%__1cHTypeIntEmake6Fiii_pk0_; +text: .text%__1cENodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNsymbolOopDescLas_C_string6kM_pc_; +text: .text%__1cKSchedulingWAddNodeToAvailableList6MpnENode__v_; +text: .text%__1cKSchedulingSChooseNodeToBundle6M_pnENode__; +text: .text%__1cKSchedulingPAddNodeToBundle6MpnENode_pknFBlock__v_; +text: .text%__1cICallNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cTconstantPoolOopDescNklass_at_impl6FnSconstantPoolHandle_ipnGThread__pnMklassOopDesc__; +text: .text%__1cJLoadPNodeGOpcode6kM_i_; +text: .text%__1cMMutableSpaceIallocate6MI_pnIHeapWord__; +text: .text%__1cJPSPermGenSallocate_permanent6MI_pnIHeapWord__; +text: .text%__1cUParallelScavengeHeapWpermanent_mem_allocate6MI_pnIHeapWord__; +text: .text%__1cIMachNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMMutableSpaceMcas_allocate6MI_pnIHeapWord__; +text: .text%__1cNflagsRegPOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cHPhiNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cMMachTypeNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cJCatchNodeGOpcode6kM_i_; +text: .text%__1cIJVMStateLdebug_start6kM_I_; +text: .text%__1cENodeHdel_req6MI_v_; +text: .text%__1cRSignatureIterator2t6MnMsymbolHandle__v_; +text: .text%__1cOAbstractICachePinvalidate_word6FpC_v_; +text: .text%__1cFBlockIis_Empty6kM_i_; +text: .text%__1cOThreadCritical2T6M_v_; +text: .text%__1cOThreadCritical2t6M_v_; +text: .text%method_compare: methodOop.o; +text: .text%__1cICodeHeapKfind_start6kMpv_1_; +text: .text%__1cETypeEhash6kM_i_; +text: .text%__1cRNativeInstructionLset_long_at6Mii_v_; +text: .text%__1cIAddPNodeLbottom_type6kM_pknEType__; +text: .text%__1cJCProjNodeEhash6kM_I_: classes.o; +text: .text%__1cIHaltNodeGOpcode6kM_i_; +text: .text%__1cFStateRMachNodeGenerator6MipnHCompile__pnIMachNode__; +text: .text%__1cHMatcherKReduceInst6MpnFState_irpnENode__pnIMachNode__; +text: .text%__1cICmpUNodeGOpcode6kM_i_; +text: .text%__1cOPhaseIdealLoopbIdom_lca_for_get_late_ctrl_internal6MpnENode_22_2_; +text: .text%__1cXPipeline_Use_Cycle_MaskCOr6Mrk0_v_; +text: .text%__1cILoadNodeEhash6kM_I_; +text: .text%__1cKTypeAryPtrKadd_offset6kMi_pknHTypePtr__; +text: .text%__1cKHandleMarkKinitialize6MpnGThread__v_; +text: .text%__1cKHandleMark2T6M_v_; +text: .text%__1cZPhaseConservativeCoalesceIcoalesce6MpnFBlock__v_; +text: .text%__1cMPhaseIterGVNZremove_globally_dead_node6MpnENode__v_; +text: .text%__1cWShouldNotReachHereNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cHPhiNodeKin_RegMask6kMI_rknHRegMask__; +text: .text%__1cILoadNodeLbottom_type6kM_pknEType__; +text: .text%JVM_ReleaseUTF; +text: .text%__1cJloadPNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cJTypeTupleEhash6kM_i_; +text: .text%__1cMflagsRegOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cObranchConPNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKoopFactoryMnew_objArray6FpnMklassOopDesc_ipnGThread__pnPobjArrayOopDesc__; +text: .text%__1cNinstanceKlassRallocate_objArray6MiipnGThread__pnPobjArrayOopDesc__; +text: .text%__1cMOopMapStreamJfind_next6M_v_; +text: .text%__1cFDictI2i6M_v_; +text: .text%__1cKNode_ArrayEgrow6MI_v_; +text: .text%__1cHTypeIntEmake6Fi_pk0_; +text: .text%__1cRAbstractAssembler2t6MpnKCodeBuffer__v_; +text: .text%__1cJloadPNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMMergeMemNodeLbottom_type6kM_pknEType__: memnode.o; +text: .text%__1cSInterpreterRuntimeJanewarray6FpnKJavaThread_pnTconstantPoolOopDesc_ii_v_; +text: .text%__1cOPSPromotionLABKinitialize6MnJMemRegion__v_; +text: .text%__1cJMultiNodeIproj_out6kMI_pnIProjNode__; +text: .text%__1cPindOffset13OperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cUcompI_iReg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cODataRelocationJset_value6MpC_v_: relocInfo.o; +text: .text%__1cKRelocationRpd_set_data_value6MpCi_v_; +text: .text%__1cKCastPPNodeGOpcode6kM_i_; +text: .text%__1cOoop_RelocationFvalue6M_pC_: relocInfo.o; +text: .text%__1cOoop_RelocationGoffset6M_i_: relocInfo.o; +text: .text%__1cPSignatureStreamEnext6M_v_; +text: .text%__1cLLShiftINodeGOpcode6kM_i_; +text: .text%__1cMPhaseChaitinSuse_prior_register6MpnENode_I2pnFBlock_rnJNode_List_6_i_; +text: .text%__1cGIfNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cGBitMapJset_union6M0_v_; +text: .text%__1cIConPNodeGOpcode6kM_i_; +text: .text%__1cJLoadINodeGOpcode6kM_i_; +text: .text%JVM_GetMethodIxExceptionTableLength; +text: .text%__1cOJNIHandleBlockPallocate_handle6MpnHoopDesc__pnI_jobject__; +text: .text%__1cPClassFileParserUassemble_annotations6MpCi1ipnGThread__nPtypeArrayHandle__; +text: .text%__1cNSharedRuntimeDd2i6Fd_i_; +text: .text%__1cVcompP_iRegP_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKRegionNodeEhash6kM_I_: classes.o; +text: .text%__1cNbranchConNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOoop_RelocationSfix_oop_relocation6M_v_; +text: .text%__1cRSignatureIteratorSiterate_parameters6M_v_; +text: .text%__1cIAddPNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cGBitMap2t6MpII_v_; +text: .text%__1cPClassFileStreamGget_u46MpnGThread__I_; +text: .text%__1cMMachCallNodeLbottom_type6kM_pknEType__; +text: .text%__1cFParsePdo_one_bytecode6M_v_; +text: .text%__1cFParseNdo_exceptions6M_v_; +text: .text%__1cHPhiNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cHMatcherKmatch_tree6MpknENode__pnIMachNode__; +text: .text%__1cMPhaseIterGVNKis_IterGVN6M_p0_: phaseX.o; +text: .text%__1cKimmI13OperIconstant6kM_i_: ad_sparc_clone.o; +text: .text%__1cCosVcurrent_stack_pointer6F_pC_; +text: .text%__1cEDict2F6kMpkv_pv_; +text: .text%__1cKRegionNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cENodeIdestruct6M_v_; +text: .text%__1cMCreateExNodeGOpcode6kM_i_; +text: .text%__1cIBoolNodeEhash6kM_I_; +text: .text%__1cNinstanceKlassWuncached_lookup_method6kMpnNsymbolOopDesc_2_pnNmethodOopDesc__; +text: .text%__1cLTypeInstPtrFxmeet6kMpknEType__3_; +text: .text%__1cKNode_ArrayFclear6M_v_; +text: .text%__1cObranchConPNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cIProjNodeHsize_of6kM_I_; +text: .text%__1cTconstantPoolOopDescWsignature_ref_index_at6Mi_i_; +text: .text%__1cMloadConINodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIHaltNodeKmatch_edge6kMI_I_: classes.o; +text: .text%__1cJloadBNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cHhashptr6Fpkv_i_; +text: .text%__1cMMachHaltNodeEjvms6kM_pnIJVMState__; +text: .text%__1cHhashkey6Fpkv_i_; +text: .text%__1cMPhaseChaitinHnew_lrg6MpknENode_I_v_; +text: .text%__1cIJVMStateJdebug_end6kM_I_; +text: .text%__1cIPhaseIFGMtest_edge_sq6kMII_i_; +text: .text%__1cJloadPNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cHSubNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cRSignatureIteratorSiterate_returntype6M_v_; +text: .text%__1cSaddP_reg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cIMachNodeHtwo_adr6kM_I_: ad_sparc.o; +text: .text%__1cNSafePointNodeHsize_of6kM_I_; +text: .text%__1cLTypeInstPtrKadd_offset6kMi_pknHTypePtr__; +text: .text%__1cHCmpNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cPcheckCastPPNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cNLoadRangeNodeGOpcode6kM_i_; +text: .text%__1cNbranchConNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cENode2t6Mp011_v_; +text: .text%__1cJStoreNodeKmatch_edge6kMI_I_; +text: .text%__1cOPSPromotionLABFflush6M_v_; +text: .text%__1cQResultTypeFinderDset6MinJBasicType__v_: bytecode.o; +text: .text%__1cOBytecodeStreamEnext6M_nJBytecodesECode__: generateOopMap.o; +text: .text%__1cOcompU_iRegNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cNmethodOopDescLresult_type6kM_nJBasicType__; +text: .text%__1cICodeHeapJnext_free6kMpnJHeapBlock__pv_; +text: .text%__1cICodeHeapLblock_start6kMpv_pnJHeapBlock__; +text: .text%__1cICodeHeapKnext_block6kMpnJHeapBlock__2_; +text: .text%__1cSCountedLoopEndNodeGOpcode6kM_i_; +text: .text%__1cPciInstanceKlassGloader6M_pnHoopDesc__; +text: .text%__1cPcheckCastPPNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cNCellTypeStateFmerge6kM0i_0_; +text: .text%__1cMPhaseIterGVNMsubsume_node6MpnENode_2_v_; +text: .text%__1cILoadNodeKmatch_edge6kMI_I_; +text: .text%__1cJloadINodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cNExceptionMark2T6M_v_; +text: .text%__1cNExceptionMark2t6MrpnGThread__v_; +text: .text%__1cITypeLongEhash6kM_i_; +text: .text%__1cJHashtableJnew_entry6MIpnHoopDesc__pnOHashtableEntry__; +text: .text%__1cJiRegLOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cKJNIHandlesKmake_local6FpnHJNIEnv__pnHoopDesc__pnI_jobject__; +text: .text%__1cPciInstanceKlassRprotection_domain6M_pnHoopDesc__; +text: .text%__1cOloadConI13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOloadConI13NodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cObranchConPNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKStoreINodeGOpcode6kM_i_; +text: .text%__1cJcmpOpOperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cRSignatureIterator2t6MpnNsymbolOopDesc__v_; +text: .text%__1cJiRegPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cKRegionNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cKstorePNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cHPhiNodeHsize_of6kM_I_: cfgnode.o; +text: .text%__1cJrelocInfoNfinish_prefix6Mph_p0_; +text: .text%__1cQaddP_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cSaddI_reg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cTAbstractInterpreterLmethod_kind6FnMmethodHandle__n0AKMethodKind__; +text: .text%__1cIMachOperDreg6kMpnNPhaseRegAlloc_pknENode_i_i_; +text: .text%__1cIBoolNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cLCounterDataKcell_count6M_i_: ciMethodData.o; +text: .text%__1cHRegMaskMClearToPairs6M_v_; +text: .text%__1cRshlI_reg_imm5NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIMachOperDreg6kMpnNPhaseRegAlloc_pknENode__i_; +text: .text%__1cNPhaseCoalesceRcombine_these_two6MpnENode_2_v_; +text: .text%__1cKcmpOpPOperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cKTypeRawPtrKadd_offset6kMi_pknHTypePtr__; +text: .text%__1cMloadConINodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cFArenaEgrow6MI_pv_; +text: .text%__1cMPhaseChaitinLinsert_proj6MpnFBlock_IpnENode_I_v_; +text: .text%__1cILoadNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cJStoreNodeLbottom_type6kM_pknEType__; +text: .text%__1cIBoolNodeLbottom_type6kM_pknEType__: subnode.o; +text: .text%__1cNSafePointNodeSset_next_exception6Mp0_v_; +text: .text%__1cQaddP_reg_regNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cIHaltNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cPCheckCastPPNodeGOpcode6kM_i_; +text: .text%__1cKStorePNodeGOpcode6kM_i_; +text: .text%__1cKRelocationLunpack_data6M_v_: relocInfo.o; +text: .text%__1cNflagsRegUOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cNinstanceKlassGvtable6kM_pnLklassVtable__; +text: .text%__1cPcheckCastPPNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cIAddPNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cRInvocationCounterEinit6M_v_; +text: .text%__1cKNode_Array2t6MpnFArena__v_: block.o; +text: .text%__1cTconstantPoolOopDescNklass_name_at6Mi_pnNsymbolOopDesc__; +text: .text%__1cXPhaseAggressiveCoalesceIcoalesce6MpnFBlock__v_; +text: .text%__1cFBlockScall_catch_cleanup6MrnLBlock_Array__v_; +text: .text%__1cObranchConUNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cTconstantPoolOopDescRname_ref_index_at6Mi_i_; +text: .text%__1cIAddINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cHRetNodeNis_block_proj6kM_pknENode__: ad_sparc_misc.o; +text: .text%__1cKRegionNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKstorePNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMObjectLocker2T6M_v_; +text: .text%__1cOcompI_iRegNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cICallNodeIIdentity6MpnOPhaseTransform__pnENode__: callnode.o; +text: .text%__1cMURShiftINodeGOpcode6kM_i_; +text: .text%__1cRmethodDataOopDescPinitialize_data6MpnOBytecodeStream_i_i_; +text: .text%__1cNRelocIteratorKset_limits6MpC1_v_; +text: .text%__1cIRootNodeGOpcode6kM_i_; +text: .text%__1cOloadConI13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJloadPNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cILoadNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cTCreateExceptionNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cFStateM_sub_Op_ConI6MpknENode__v_; +text: .text%__1cPcheckCastPPNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cISubINodeGOpcode6kM_i_; +text: .text%__1cNbranchConNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJTypeTupleEmake6FIppknEType__pk0_; +text: .text%__1cJTypeTupleGfields6FI_ppknEType__; +text: .text%__1cENodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cLSymbolTableJbasic_add6MipCiIpnGThread__pnNsymbolOopDesc__; +text: .text%__1cLsymbolKlassPallocate_symbol6MpCipnGThread__pnNsymbolOopDesc__; +text: .text%__1cSinstanceKlassKlassIoop_size6kMpnHoopDesc__i_; +text: .text%__1cRAbstractAssemblerEbind6MrnFLabel__v_; +text: .text%__1cKbranchNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cHPhiNodeIadr_type6kM_pknHTypePtr__: cfgnode.o; +text: .text%__1cHAddNodeEhash6kM_I_; +text: .text%__1cENodeRdisconnect_inputs6Mp0_i_; +text: .text%__1cPsplit_flow_path6FpnIPhaseGVN_pnHPhiNode__pnENode__: cfgnode.o; +text: .text%__1cSaddI_reg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cJFieldTypeKbasic_type6FpnNsymbolOopDesc__nJBasicType__; +text: .text%__1cHConNodeEhash6kM_I_; +text: .text%__1cLLShiftINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cNmethodOopDescIbci_from6kMpC_i_; +text: .text%__1cOMachReturnNodeIadr_type6kM_pknHTypePtr__; +text: .text%__1cNidealize_test6FpnIPhaseGVN_pnGIfNode__3_: ifnode.o; +text: .text%__1cITypeNodeHsize_of6kM_I_; +text: .text%__1cNSafePointNodeLbottom_type6kM_pknEType__: callnode.o; +text: .text%__1cTconstantPoolOopDescSklass_at_if_loaded6FnSconstantPoolHandle_i_pnMklassOopDesc__; +text: .text%__1cJloadINodeIpipeline6kM_pknIPipeline__; +text: .text%JVM_GetClassModifiers; +text: .text%__1cJCodeCacheJfind_blob6Fpv_pnICodeBlob__; +text: .text%__1cNSafePointNodeOnext_exception6kM_p0_; +text: .text%JVM_GetClassAccessFlags; +text: .text%__1cLklassItable2t6MnTinstanceKlassHandle__v_; +text: .text%__1cIsplit_if6FpnGIfNode_pnMPhaseIterGVN__pnENode__: ifnode.o; +text: .text%__1cHTypeAryEhash6kM_i_; +text: .text%__1cPfieldDescriptorKinitialize6MpnMklassOopDesc_i_v_; +text: .text%__1cJMultiNodeFmatch6MpknIProjNode_pknHMatcher__pnENode__; +text: .text%__1cJCProjNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPPerfLongVariantGsample6M_v_; +text: .text%__1cJStoreNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cMPhaseChaitinMyank_if_dead6MpnENode_pnFBlock_pnJNode_List_6_i_; +text: .text%__1cJCatchNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cIMachOperNconstant_disp6kM_i_; +text: .text%__1cIMachOperFscale6kM_i_; +text: .text%__1cENode2t6Mp0111_v_; +text: .text%__1cFPhase2t6Mn0ALPhaseNumber__v_; +text: .text%__1cNCompileBrokerLmaybe_block6F_v_; +text: .text%__1cFBlockOcode_alignment6M_I_; +text: .text%__1cNinstanceKlassGitable6kM_pnLklassItable__; +text: .text%__1cLciSignatureLreturn_type6kM_pnGciType__; +text: .text%__1cFStateM_sub_Op_RegP6MpknENode__v_; +text: .text%JVM_GetCPMethodSignatureUTF; +text: .text%__1cFChunkJnext_chop6M_v_; +text: .text%__1cMMergeMemNodeEhash6kM_I_; +text: .text%__1cKSchedulingbFComputeRegisterAntidependencies6MpnFBlock__v_; +text: .text%__1cKSchedulingPComputeUseCount6MpknFBlock__v_; +text: .text%__1cHTypePtrHget_con6kM_i_; +text: .text%__1cNinstanceKlassRprotection_domain6M_pnHoopDesc__: instanceKlass.o; +text: .text%__1cIMachNodePcompute_padding6kMi_i_: ad_sparc.o; +text: .text%__1cIMachNodeSalignment_required6kM_i_: ad_sparc.o; +text: .text%__1cMPhaseChaitinSget_spillcopy_wide6MpnENode_2I_2_; +text: .text%__1cYDebugInformationRecorderTcreate_scope_values6MpnNGrowableArray4CpnKScopeValue____pnKDebugToken__; +text: .text%__1cWstatic_stub_RelocationLunpack_data6M_v_; +text: .text%__1cQaddI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cObranchConUNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cFBlockJfind_node6kMpknENode__I_; +text: .text%__1cUArgumentSizeComputerDset6MinJBasicType__v_: frame.o; +text: .text%__1cHCmpNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cNCollectedHeapXallocate_from_tlab_slow6FpnGThread_I_pnIHeapWord__; +text: .text%__1cWThreadLocalAllocBufferXclear_before_allocation6M_v_; +text: .text%__1cHTypePtrEhash6kM_i_; +text: .text%__1cNinstanceKlassRallocate_instance6MpnGThread__pnPinstanceOopDesc__; +text: .text%__1cSObjectSynchronizerKslow_enter6FnGHandle_pnJBasicLock_pnGThread__v_; +text: .text%__1cWThreadLocalAllocBufferEfill6MpnIHeapWord_2I_v_; +text: .text%__1cUParallelScavengeHeapRallocate_new_tlab6MI_pnIHeapWord__; +text: .text%__1cYNoJvmtiVMObjectAllocMark2t6M_v_; +text: .text%__1cYNoJvmtiVMObjectAllocMark2T6M_v_; +text: .text%__1cFBlockLfind_remove6MpknENode__v_; +text: .text%__1cIIndexSetJlrg_union6MIIkIpknIPhaseIFG_rknHRegMask__I_; +text: .text%__1cKMemBarNodeKmatch_edge6kMI_I_: classes.o; +text: .text%__1cUcompI_iReg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cMLinkResolverbAcheck_method_accessability6FnLKlassHandle_11nMmethodHandle_pnGThread__v_; +text: .text%__1cNObjectMonitorEexit6MpnGThread__v_; +text: .text%__1cIimmPOperEtype6kM_pknEType__: ad_sparc_clone.o; +text: .text%__1cMloadConPNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cLMachNopNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJloadINodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cNloadRangeNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cVCompressedWriteStream2t6Mi_v_; +text: .text%__1cNObjectMonitorFenter6MpnGThread__v_; +text: .text%__1cENodeKreplace_by6Mp0_v_; +text: .text%__1cSObjectSynchronizerJslow_exit6FpnHoopDesc_pnJBasicLock_pnGThread__v_; +text: .text%__1cMMergeMemNodePiteration_setup6Mpk0_v_; +text: .text%__1cFKlassNlookup_method6kMpnNsymbolOopDesc_2_pnNmethodOopDesc__; +text: .text%__1cKDictionaryEfind6MiInMsymbolHandle_nGHandle_2pnGThread__pnMklassOopDesc__; +text: .text%__1cRMachSpillCopyNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cKRegionNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cJStoreNodeEhash6kM_I_; +text: .text%__1cSaddP_reg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cQaddI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cIGraphKitJclone_map6M_pnNSafePointNode__; +text: .text%__1cKIfTrueNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cRMemBarReleaseNodeGOpcode6kM_i_; +text: .text%__1cKbranchNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIMachOperIconstant6kM_i_; +text: .text%__1cWMutableSpaceUsedHelperLtake_sample6M_x_: spaceCounters.o; +text: .text%__1cGPcDescHreal_pc6kMpknHnmethod__pC_; +text: .text%__1cRPSOldPromotionLABFflush6M_v_; +text: .text%__1cTconstantPoolOopDescMklass_ref_at6MipnGThread__pnMklassOopDesc__; +text: .text%__1cPcompP_iRegPNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cLBoxLockNodeGOpcode6kM_i_; +text: .text%__1cIciObjectJset_ident6MI_v_; +text: .text%__1cKJNIHandlesKmake_local6FpnHoopDesc__pnI_jobject__; +text: .text%__1cKTypeRawPtrEhash6kM_i_; +text: .text%__1cIBoolNodeKmatch_edge6kMI_I_: subnode.o; +text: .text%__1cMMergeMemNodePset_base_memory6MpnENode__v_; +text: .text%__1cLIfFalseNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cCosPelapsed_counter6F_x_; +text: .text%__1cGBitMapOset_difference6M0_v_; +text: .text%__1cNSafePointNodeEjvms6kM_pnIJVMState__: callnode.o; +text: .text%__1cOoop_RelocationEtype6M_nJrelocInfoJrelocType__: relocInfo.o; +text: .text%__1cMMergeMemNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%JVM_GetMethodIxLocalsCount; +text: .text%__1cNloadRangeNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%JVM_CurrentThread; +text: .text%__1cENodeHget_ptr6kM_i_; +text: .text%__1cRcmpFastUnlockNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIAndINodeGOpcode6kM_i_; +text: .text%__1cPClassFileParserYverify_legal_method_name6MnMsymbolHandle_pnGThread__v_; +text: .text%__1cENodeHins_req6MIp0_v_; +text: .text%__1cMPhaseChaitinFUnion6MpknENode_3_v_; +text: .text%__1cMloadConLNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cHAddNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cKRelocationEtype6M_nJrelocInfoJrelocType__: relocInfo.o; +text: .text%__1cKstoreINodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cOFastUnlockNodeGOpcode6kM_i_; +text: .text%__1cITypeNodeDcmp6kMrknENode__I_; +text: .text%__1cIHaltNodeLbottom_type6kM_pknEType__; +text: .text%__1cKstorePNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKcmpOpUOperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cLstoreI0NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIciObject2t6MnGHandle__v_; +text: .text%__1cNSafePointNodeKmatch_edge6kMI_I_; +text: .text%__1cIMachOperOindex_position6kM_i_; +text: .text%__1cXmembar_release_lockNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJVectorSet2L6MI_rnDSet__; +text: .text%__1cOcompU_iRegNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMMergeMemNodeJmemory_at6kMI_pnENode__; +text: .text%__1cSaddP_reg_imm13NodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cPindOffset13OperNconstant_disp6kM_i_: ad_sparc.o; +text: .text%__1cPindOffset13OperFscale6kM_i_: ad_sparc.o; +text: .text%__1cPindOffset13OperNbase_position6kM_i_: ad_sparc.o; +text: .text%__1cWShouldNotReachHereNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cPciObjectFactoryRcreate_new_object6MpnHoopDesc__pnIciObject__; +text: .text%__1cUcompI_iReg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cVcompP_iRegP_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQaddP_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQaddP_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cMLinkResolverZcheck_klass_accessability6FnLKlassHandle_1pnGThread__v_; +text: .text%__1cIJVMStateIof_depth6kMi_p0_; +text: .text%__1cNSharedRuntimeElrem6Fxx_x_; +text: .text%__1cRconstantPoolKlassIoop_size6kMpnHoopDesc__i_; +text: .text%__1cMciMethodDataLbci_to_data6Mi_pnLProfileData__; +text: .text%__1cRMemBarAcquireNodeGOpcode6kM_i_; +text: .text%__1cKo0RegPOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cSaddI_reg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cObranchConUNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJVectorSet2t6MpnFArena__v_; +text: .text%__1cKTypeAryPtrFxmeet6kMpknEType__3_; +text: .text%__1cVcompP_iRegP_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRSignatureIteratorSiterate_parameters6MX_v_; +text: .text%__1cICallNodeFmatch6MpknIProjNode_pknHMatcher__pnENode__; +text: .text%__1cJTraceTime2T6M_v_; +text: .text%__1cITypeNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cPcheckCastPPNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKMemBarNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cSconstMethodOopDescZset_inlined_tables_length6Miii_v_; +text: .text%__1cNmethodOopDescbAcompute_size_of_parameters6MpnGThread__v_; +text: .text%__1cSconstMethodOopDescLobject_size6Fiiii_i_; +text: .text%__1cLmethodKlassIallocate6MnRconstMethodHandle_nLAccessFlags_pnGThread__pnNmethodOopDesc__; +text: .text%__1cMMergeMemNodeNset_memory_at6MIpnENode__v_; +text: .text%__1cLstoreI0NodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cNSignatureInfoHdo_void6M_v_: bytecode.o; +text: .text%__1cQaddI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cENode2t6Mp01_v_; +text: .text%__1cNinstanceKlassKfind_field6kMpnNsymbolOopDesc_2pnPfieldDescriptor__pnMklassOopDesc__; +text: .text%__1cKstoreINodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cRshrI_reg_imm5NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cFStateM_sub_Op_AddP6MpknENode__v_; +text: .text%__1cTCreateExceptionNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cITypeFuncEhash6kM_i_; +text: .text%__1cLBoxLockNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cMTypeKlassPtrEhash6kM_i_; +text: .text%__1cMCallLeafNodeGOpcode6kM_i_; +text: .text%__1cSCallLeafDirectNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cHPhiNodeEmake6FpnENode_2pknEType_pknHTypePtr__p0_; +text: .text%__1cIAddPNodeQmach_bottom_type6FpknIMachNode__pknEType__; +text: .text%__1cOcompU_iRegNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cJiRegLOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cNflagsRegPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cHOrINodeGOpcode6kM_i_; +text: .text%__1cXmembar_acquire_lockNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%JVM_GetCPMethodClassNameUTF; +text: .text%__1cMloadConDNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMflagsRegOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cLProfileDataPfollow_contents6M_v_: ciMethodData.o; +text: .text%__1cLProfileDataPadjust_pointers6M_v_: ciMethodData.o; +text: .text%__1cFStateM_sub_Op_RegI6MpknENode__v_; +text: .text%__1cKklassKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cFKlassXfollow_weak_klass_links6MpnRBoolObjectClosure_pnKOopClosure__v_; +text: .text%__1cJMarkSweepXrevisit_weak_klass_link6FpnFKlass__v_; +text: .text%__1cKklassKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cWconstantPoolCacheKlassIoop_size6kMpnHoopDesc__i_; +text: .text%__1cHCompileYout_preserve_stack_slots6F_I_; +text: .text%__1cIGraphKitLclean_stack6Mi_v_; +text: .text%__1cKStoreBNodeGOpcode6kM_i_; +text: .text%__1cLklassVtableToop_adjust_pointers6M_v_; +text: .text%__1cLklassVtableToop_follow_contents6M_v_; +text: .text%__1cSconstMethodOopDescbBcompressed_linenumber_table6kM_pC_; +text: .text%__1cJlabelOperFlabel6kM_pnFLabel__: ad_sparc.o; +text: .text%__1cLciSignatureHtype_at6kMi_pnGciType__; +text: .text%__1cIMachNodeIadr_type6kM_pknHTypePtr__; +text: .text%__1cIMachOperMdisp_as_type6kM_pknHTypePtr__: ad_sparc.o; +text: .text%__1cRshlI_reg_imm5NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%JVM_IsNaN; +text: .text%__1cNloadRangeNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cKbranchNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cJStartNodeGOpcode6kM_i_; +text: .text%__1cQregF_to_stkINodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cENodeDcmp6kMrk0_I_; +text: .text%__1cHTypeIntFxdual6kM_pknEType__; +text: .text%__1cIciObjectIencoding6M_pnI_jobject__; +text: .text%__1cMmerge_region6FpnKRegionNode_pnIPhaseGVN__pnENode__: cfgnode.o; +text: .text%__1cJAssemblerOpatched_branch6Fiii_i_; +text: .text%__1cJAssemblerSbranch_destination6Fii_i_; +text: .text%__1cRshlI_reg_imm5NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cENodeIadd_prec6Mp0_v_; +text: .text%__1cLBoxLockNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cPSignatureStreamJas_symbol6MpnGThread__pnNsymbolOopDesc__; +text: .text%__1cSaddP_reg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cWMachCallStaticJavaNodePret_addr_offset6M_i_; +text: .text%__1cITypeFuncEmake6FpknJTypeTuple_3_pk0_; +text: .text%__1cMloadConDNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSCallLeafDirectNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKTypeOopPtrHget_con6kM_i_; +text: .text%__1cQsubI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIRootNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cJloadLNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cMLinkResolverZcheck_field_accessability6FnLKlassHandle_11rnPfieldDescriptor_pnGThread__v_; +text: .text%__1cJLoadBNodeGOpcode6kM_i_; +text: .text%__1cOGenerateOopMapHinterp16MpnOBytecodeStream__v_; +text: .text%__1cSvframeStreamCommonEnext6M_v_; +text: .text%__1cIAddINodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cIRootNodeNis_block_proj6kM_pknENode__: classes.o; +text: .text%__1cMMergeMemNode2t6MpnENode__v_; +text: .text%__1cOcompI_iRegNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cRMachSafePointNodeKin_RegMask6kMI_rknHRegMask__; +text: .text%__1cJloadINodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPindOffset13OperEdisp6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cPindOffset13OperEbase6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cPindOffset13OperFindex6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cICmpPNodeDsub6kMpknEType_3_3_; +text: .text%__1cHMemNodeQIdeal_DU_postCCP6MpnIPhaseCCP__pnENode__; +text: .text%__1cIGraphKitQkill_dead_locals6M_v_; +text: .text%__1cCosMvm_page_size6F_i_; +text: .text%__1cRlock_ptr_RegPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cVcompP_iRegP_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cUcompI_iReg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNSignatureInfoJdo_object6Mii_v_: bytecode.o; +text: .text%__1cRconstantPoolKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cNinstanceKlassUadjust_static_fields6M_v_; +text: .text%__1cRconstantPoolKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cLklassItableToop_adjust_pointers6M_v_; +text: .text%__1cNinstanceKlassUfollow_static_fields6M_v_; +text: .text%__1cLklassItableToop_follow_contents6M_v_; +text: .text%__1cSinstanceKlassKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cNinstanceKlassXfollow_weak_klass_links6MpnRBoolObjectClosure_pnKOopClosure__v_; +text: .text%__1cSinstanceKlassKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cNSafePointNodeGOpcode6kM_i_; +text: .text%__1cJLoadPNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cMPhaseChaitinPset_was_spilled6MpnENode__v_; +text: .text%__1cYDebugInformationRecorderVcreate_monitor_values6MpnNGrowableArray4CpnMMonitorValue____pnKDebugToken__; +text: .text%__1cMloadConPNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIGraphKit2t6MpnIJVMState__v_; +text: .text%__1cPconvI2L_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cQPreserveJVMState2T6M_v_; +text: .text%__1cRshrI_reg_imm5NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cWconstantPoolCacheKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cWconstantPoolCacheKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cTCreateExceptionNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cXmembar_release_lockNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMloadConLNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cLConvI2LNodeGOpcode6kM_i_; +text: .text%__1cITypeLongFxmeet6kMpknEType__3_; +text: .text%__1cNinstanceKlassKinitialize6MpnGThread__v_; +text: .text%__1cFParseMmerge_common6Mpn0AFBlock_i_v_; +text: .text%__1cPciInstanceKlassYunique_concrete_subklass6M_p0_; +text: .text%__1cLBoxLockNodeHsize_of6kM_I_; +text: .text%__1cOPhaseIdealLoopIset_idom6MpnENode_2I_v_; +text: .text%JVM_GetCPFieldClassNameUTF; +text: .text%__1cSaddI_reg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNLoadKlassNodeGOpcode6kM_i_; +text: .text%__1cRcmpFastUnlockNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cPciInstanceKlassLfield_cache6M_pnTciConstantPoolCache__; +text: .text%__1cFciEnvSget_field_by_index6MpnPciInstanceKlass_i_pnHciField__; +text: .text%__1cOcompI_iRegNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRshlI_reg_imm5NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNmethodOopDescIbcp_from6kMi_pC_; +text: .text%__1cICmpINodeDsub6kMpknEType_3_3_; +text: .text%__1cLRShiftINodeGOpcode6kM_i_; +text: .text%__1cOtypeArrayKlassSallocate_permanent6MipnGThread__pnQtypeArrayOopDesc__; +text: .text%__1cSCallLeafDirectNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cPcheckCastPPNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOPhaseIdealLoopQconditional_move6MpnENode__2_; +text: .text%__1cJStoreNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cITypeFuncEmake6FpnIciMethod__pk0_; +text: .text%__1cOGenerateOopMapEpush6MnNCellTypeState__v_; +text: .text%__1cJloadSNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cKStoreCNodeGOpcode6kM_i_; +text: .text%__1cOGenerateOopMapRdo_exception_edge6MpnOBytecodeStream__v_; +text: .text%__1cMstringStreamFwrite6MpkcI_v_; +text: .text%__1cOGenerateOopMapDpop6M_nNCellTypeState__; +text: .text%__1cHRetNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cPcmpFastLockNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMLinkResolverMresolve_pool6FrnLKlassHandle_rnMsymbolHandle_42nSconstantPoolHandle_ipnGThread__v_; +text: .text%__1cMLinkResolverOresolve_invoke6FrnICallInfo_nGHandle_nSconstantPoolHandle_inJBytecodesECode_pnGThread__v_; +text: .text%__1cIBoolNodeJideal_reg6kM_I_: subnode.o; +text: .text%__1cHCmpNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cRloadConP_pollNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cETypeFwiden6kMpk0_2_: type.o; +text: .text%__1cLstoreI0NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cFciEnvTget_method_by_index6MpnPciInstanceKlass_inJBytecodesECode__pnIciMethod__; +text: .text%__1cFciEnvYget_method_by_index_impl6MpnPciInstanceKlass_inJBytecodesECode__pnIciMethod__; +text: .text%__1cMloadConPNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cFciEnvNlookup_method6MpnNinstanceKlass_2pnNsymbolOopDesc_4nJBytecodesECode__pnNmethodOopDesc__; +text: .text%__1cKDictionaryKfind_class6MiInMsymbolHandle_nGHandle__pnMklassOopDesc__; +text: .text%__1cPcompP_iRegPNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cNloadRangeNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNCatchProjNodeLbottom_type6kM_pknEType__: cfgnode.o; +text: .text%__1cNCatchProjNodeHsize_of6kM_I_: cfgnode.o; +text: .text%__1cFStateK_sub_Op_If6MpknENode__v_; +text: .text%__1cTciConstantPoolCacheDget6Mi_pv_; +text: .text%__1cSInterpreterRuntimeMmonitorenter6FpnKJavaThread_pnPBasicObjectLock__v_; +text: .text%__1cSInterpreterRuntimePresolve_get_put6FpnKJavaThread_nJBytecodesECode__v_; +text: .text%__1cQsubI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cXmembar_acquire_lockNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQaddP_reg_regNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cPCountedLoopNodeGOpcode6kM_i_; +text: .text%__1cSInterpreterRuntimeLmonitorexit6FpnKJavaThread_pnPBasicObjectLock__v_; +text: .text%__1cIAndLNodeGOpcode6kM_i_; +text: .text%__1cIGraphKitOset_all_memory6MpnENode__v_; +text: .text%__1cQSystemDictionarybEresolve_instance_class_or_null6FnMsymbolHandle_nGHandle_2pnGThread__pnMklassOopDesc__; +text: .text%__1cVjava_lang_ClassLoaderbBnon_reflection_class_loader6FpnHoopDesc__2_; +text: .text%__1cFParseFBlockKinit_graph6Mp0_v_; +text: .text%__1cMTypeKlassPtrEmake6FnHTypePtrDPTR_pnHciKlass_i_pk0_; +text: .text%__1cKRelocationLspec_simple6FnJrelocInfoJrelocType__nQRelocationHolder__; +text: .text%__1cCosGmalloc6FI_pv_; +text: .text%__1cSInterpreterRuntimeOresolve_invoke6FpnKJavaThread_nJBytecodesECode__v_; +text: .text%__1cIGraphKitTadd_exception_state6MpnNSafePointNode__v_; +text: .text%__1cIimmPOperIconstant6kM_i_: ad_sparc_clone.o; +text: .text%__1cIregDOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cKstoreINodeIpipeline6kM_pknIPipeline__; +text: .text%__1cICodeHeapLheader_size6F_I_; +text: .text%__1cWConstantPoolCacheEntryKset_method6MnJBytecodesECode_nMmethodHandle_i_v_; +text: .text%__1cNloadRangeNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cFParseMdo_one_block6M_v_; +text: .text%__1cOPhaseIdealLoopRregister_new_node6MpnENode_2_v_; +text: .text%__1cLstoreB0NodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cIAddINodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cIJVMStateLdebug_depth6kM_I_; +text: .text%__1cENodeNadd_req_batch6Mp0I_v_; +text: .text%__1cKciTypeFlowLStateVectorOpush_translate6MpnGciType__v_; +text: .text%__1cJloadFNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cPVirtualCallDataKcell_count6M_i_: ciMethodData.o; +text: .text%__1cIMachNodeOpipeline_class6F_pknIPipeline__; +text: .text%__1cQSystemDictionarybCfind_instance_or_array_klass6FnMsymbolHandle_nGHandle_2pnGThread__pnMklassOopDesc__; +text: .text%__1cIPhaseGVNUtransform_no_reclaim6MpnENode__2_; +text: .text%__1cIAddLNodeGOpcode6kM_i_; +text: .text%__1cLLShiftINodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cOMethodLivenessKBasicBlockJpropagate6Mp0_v_; +text: .text%__1cKciTypeFlowGJsrSet2t6MpnFArena_i_v_; +text: .text%__1cHMatcherKmatch_sfpt6MpnNSafePointNode__pnIMachNode__; +text: .text%__1cMFastLockNodeGOpcode6kM_i_; +text: .text%__1cLConvL2INodeGOpcode6kM_i_; +text: .text%__1cIXorINodeGOpcode6kM_i_; +text: .text%__1cMVirtualSpaceOcommitted_size6kM_I_; +text: .text%__1cOcompU_iRegNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPorI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKTypeAryPtrFklass6kM_pnHciKlass__; +text: .text%__1cIGraphKitbDtransfer_exceptions_into_jvms6M_pnIJVMState__; +text: .text%__1cLTypeInstPtrFxdual6kM_pknEType__; +text: .text%__1cNLoadRangeNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cFBlockKsched_call6MrnHMatcher_rnLBlock_Array_IrnJNode_List_pipnMMachCallNode_rnJVectorSet__I_; +text: .text%__1cSsafePoint_pollNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cILoadNodeHsize_of6kM_I_; +text: .text%__1cRInterpretedRFrameKtop_method6kM_nMmethodHandle__: rframe.o; +text: .text%__1cIGraphKitJsync_jvms6kM_pnIJVMState__; +text: .text%__1cICmpUNodeDsub6kMpknEType_3_3_; +text: .text%__1cEUTF8Hstrrchr6FpWiW_1_; +text: .text%__1cPcompP_iRegPNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cPsp_ptr_RegPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cPClassFileParserbCverify_legal_field_signature6MnMsymbolHandle_1pnGThread__v_; +text: .text%__1cPClassFileParserXverify_legal_field_name6MnMsymbolHandle_pnGThread__v_; +text: .text%__1cRshrP_reg_imm5NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cLBoxLockNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cITypeLongEmake6Fxxi_pk0_; +text: .text%__1cNloadKlassNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%JVM_GetCPMethodNameUTF; +text: .text%__1cMtlsLoadPNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cLstoreB0NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIimmIOperIconstant6kM_i_: ad_sparc_clone.o; +text: .text%__1cNSharedRuntimeEldiv6Fxx_x_; +text: .text%__1cHBitDataKcell_count6M_i_: ciMethodData.o; +text: .text%__1cURethrowExceptionNodeNis_block_proj6kM_pknENode__: ad_sparc_misc.o; +text: .text%__1cQSystemDictionarybOfind_constrained_instance_or_array_klass6FnMsymbolHandle_nGHandle_pnGThread__pnMklassOopDesc__; +text: .text%__1cQsubI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJloadBNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIciSymbol2t6MnMsymbolHandle__v_; +text: .text%__1cQaddP_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKmethodOperGmethod6kM_i_: ad_sparc.o; +text: .text%__1cFKlassIsubklass6kM_p0_; +text: .text%__1cNinstanceKlassbBallocate_permanent_instance6MpnGThread__pnPinstanceOopDesc__; +text: .text%__1cXInterpreterFrameClosureJoffset_do6Mi_v_: frame.o; +text: .text%__1cTconstantPoolOopDescOstring_at_impl6FnSconstantPoolHandle_ipnGThread__pnHoopDesc__; +text: .text%__1cEUTF8Sconvert_to_unicode6FpkcpHi_v_; +text: .text%__1cIMulLNodeGOpcode6kM_i_; +text: .text%__1cKReturnNodeKmatch_edge6kMI_I_; +text: .text%__1cGOopMap2t6Mii_v_; +text: .text%__1cNloadConP0NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cJLoadSNodeGOpcode6kM_i_; +text: .text%__1cLPCTableNodeLbottom_type6kM_pknEType__; +text: .text%__1cKBranchDataKcell_count6M_i_: ciMethodData.o; +text: .text%__1cMCreateExNodeKmatch_edge6kMI_I_: classes.o; +text: .text%__1cRloadConP_pollNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cJCodeCacheEnext6FpnICodeBlob__2_; +text: .text%__1cRcmpFastUnlockNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cJLoadLNodeGOpcode6kM_i_; +text: .text%__1cMciMethodDataLhas_trap_at6MpnLProfileData_i_i_; +text: .text%__1cPThreadLocalNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cKReturnNodeGOpcode6kM_i_; +text: .text%__1cNinstanceKlassPinitialize_impl6FnTinstanceKlassHandle_pnGThread__v_; +text: .text%__1cTconstantPoolOopDescbBbasic_type_for_signature_at6Mi_nJBasicType__; +text: .text%__1cNflagsRegUOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cMloadConINodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cNCatchProjNodeEhash6kM_I_; +text: .text%__1cEUTF8Ounicode_length6Fpkci_i_; +text: .text%__1cHCompileTProcess_OopMap_Node6MpnIMachNode_i_v_; +text: .text%__1cNCallGenerator2t6MpnIciMethod__v_; +text: .text%__1cKCompiledIC2t6MpnKRelocation__v_; +text: .text%__1cKCompiledICOic_destination6kM_pC_; +text: .text%__1cHTypeAryFxmeet6kMpknEType__3_; +text: .text%__1cICallNodeJideal_reg6kM_I_: callnode.o; +text: .text%__1cLStringTableGintern6FpnNsymbolOopDesc_pnGThread__pnHoopDesc__; +text: .text%__1cNsymbolOopDescKas_unicode6kMri_pH_; +text: .text%__1cPmethodDataKlassIoop_size6kMpnHoopDesc__i_; +text: .text%__1cKciTypeFlowQadd_to_work_list6Mpn0AFBlock__v_; +text: .text%__1cKciTypeFlowKflow_block6Mpn0AFBlock_pn0ALStateVector_pn0AGJsrSet__v_; +text: .text%__1cEUTF8Enext6FpkcpH_pc_; +text: .text%__1cJVectorSetFClear6M_v_; +text: .text%__1cHCompileSflatten_alias_type6kMpknHTypePtr__3_; +text: .text%__1cCosEfree6Fpv_v_; +text: .text%__1cRshrI_reg_imm5NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cPcmpFastLockNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cYciExceptionHandlerStreamFcount6M_i_; +text: .text%__1cKciTypeFlowFBlockScompute_exceptions6M_v_; +text: .text%__1cIPhaseIFGFUnion6MII_v_; +text: .text%__1cYCallStaticJavaDirectNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cILoopNodeGOpcode6kM_i_; +text: .text%__1cICmpLNodeGOpcode6kM_i_; +text: .text%__1cOPhaseIdealLoopGspinup6MpnENode_2222pnLsmall_cache__2_; +text: .text%__1cQaddI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cMindIndexOperJnum_edges6kM_I_: ad_sparc.o; +text: .text%__1cIConLNodeGOpcode6kM_i_; +text: .text%JVM_GetCPFieldSignatureUTF; +text: .text%__1cENodeLnonnull_req6kM_p0_; +text: .text%__1cYCallStaticJavaDirectNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cYCallStaticJavaDirectNodeKmethod_set6Mi_v_; +text: .text%__1cMelapsedTimerFstart6M_v_; +text: .text%__1cMelapsedTimerEstop6M_v_; +text: .text%__1cMURShiftINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cSaddP_reg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOPhaseIdealLoopOfind_use_block6MpnENode_22222_2_; +text: .text%__1cOPhaseIdealLoopKhandle_use6MpnENode_2pnLsmall_cache_22222_v_; +text: .text%jni_DeleteLocalRef: jni.o; +text: .text%__1cIGraphKit2t6M_v_; +text: .text%__1cMoutputStreamDput6Mc_v_; +text: .text%__1cIGraphKitNset_map_clone6MpnNSafePointNode__v_; +text: .text%__1cRInterpretedRFrameEinit6M_v_; +text: .text%__1cHMulNodeEhash6kM_I_; +text: .text%__1cENodeJset_req_X6MIp0pnMPhaseIterGVN__v_; +text: .text%__1cJLoadINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cINodeHashLhash_insert6MpnENode__v_; +text: .text%__1cKstoreCNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cENodeLbottom_type6kM_pknEType__; +text: .text%__1cKJNIHandlesKmake_local6FpnGThread_pnHoopDesc__pnI_jobject__; +text: .text%__1cKstoreCNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIAddPNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cQjava_lang_StringbBcreate_tenured_from_unicode6FpHipnGThread__nGHandle__; +text: .text%__1cKoopFactoryXnew_permanent_charArray6FipnGThread__pnQtypeArrayOopDesc__; +text: .text%__1cKMemBarNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cGvframe2t6MpknFframe_pknLRegisterMap_pnKJavaThread__v_; +text: .text%__1cLRegisterMap2t6Mpk0_v_; +text: .text%__1cXmembar_acquire_lockNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOcompI_iRegNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cIciSymbolEmake6Fpkc_p0_; +text: .text%__1cPorI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cGPcDesc2t6Miii_v_; +text: .text%__1cHCompileKalias_type6MpnHciField__pn0AJAliasType__; +text: .text%__1cGvframeKnew_vframe6FpknFframe_pknLRegisterMap_pnKJavaThread__p0_; +text: .text%__1cPconvI2L_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMtlsLoadPNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cYcompareAndSwapL_boolNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cIAddINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cIciMethodRget_flow_analysis6M_pnKciTypeFlow__; +text: .text%__1cWCallLeafNoFPDirectNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cSmembar_acquireNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKbranchNodeJlabel_set6MrnFLabel_I_v_; +text: .text%__1cKbranchNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOloadConI13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSaddL_reg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%jni_GetObjectField: jni.o; +text: .text%__1cSMemBarCPUOrderNodeGOpcode6kM_i_; +text: .text%__1cJFieldTypeOget_array_info6FpnNsymbolOopDesc_pip2pnGThread__nJBasicType__; +text: .text%__1cQandL_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cWstatic_stub_RelocationEtype6M_nJrelocInfoJrelocType__: relocInfo.o; +text: .text%__1cQaddL_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cNloadKlassNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cPmethodDataKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cPmethodDataKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cJloadBNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cYcompareAndSwapL_boolNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cRMachNullCheckNodeKin_RegMask6kMI_rknHRegMask__; +text: .text%__1cOPhaseIdealLoopIsink_use6MpnENode_2_v_; +text: .text%__1cIGraphKitOreplace_in_map6MpnENode_2_v_; +text: .text%__1cNinstanceKlassLfind_method6kMpnNsymbolOopDesc_2_pnNmethodOopDesc__; +text: .text%__1cHCompileKTracePhase2T6M_v_; +text: .text%__1cMPhaseChaitinLclone_projs6MpnFBlock_IpnENode_4rI_i_; +text: .text%__1cNinstanceKlassSlookup_osr_nmethod6kMkpnNmethodOopDesc_i_pnHnmethod__; +text: .text%__1cIJVMState2t6MpnIciMethod_p0_v_; +text: .text%__1cIHaltNode2t6MpnENode_2_v_; +text: .text%__1cLOptoRuntimeSuncommon_trap_Type6F_pknITypeFunc__; +text: .text%__1cJloadLNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cSsafePoint_pollNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cINodeHashJhash_find6MpknENode__p1_; +text: .text%__1cQmulL_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cSaddP_reg_imm13NodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cOMethodLivenessKBasicBlock2t6Mp0ii_v_; +text: .text%__1cOMethodLivenessKBasicBlockQcompute_gen_kill6MpnIciMethod__v_; +text: .text%__1cOGenerateOopMapFppush6MpnNCellTypeState__v_; +text: .text%__1cJTypeTupleKmake_range6FpnLciSignature__pk0_; +text: .text%__1cJTypeTupleLmake_domain6FpnPciInstanceKlass_pnLciSignature__pk0_; +text: .text%__1cSmembar_acquireNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMWarmCallInfoKalways_hot6F_p0_; +text: .text%__1cTCreateExceptionNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cLstoreB0NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMtlsLoadPNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cLBoxLockNodeKin_RegMask6kMI_rknHRegMask__; +text: .text%__1cITypeLongEmake6Fx_pk0_; +text: .text%__1cHciFieldPinitialize_from6MpnPfieldDescriptor__v_; +text: .text%__1cKimmI13OperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cJloadBNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIGraphKitZadd_exception_states_from6MpnIJVMState__v_; +text: .text%__1cMPhaseChaitinNFind_compress6MpknENode__I_; +text: .text%__1cQSystemDictionaryEfind6FnMsymbolHandle_nGHandle_2pnGThread__pnMklassOopDesc__; +text: .text%__1cHPhiNodeEmake6FpnENode_2_p0_; +text: .text%__1cNCatchProjNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cWCallLeafNoFPDirectNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cIciMethodTcall_profile_at_bci6Mi_nNciCallProfile__; +text: .text%__1cIProjNodeDcmp6kMrknENode__I_; +text: .text%__1cLklassVtableIindex_of6kMpnNmethodOopDesc_i_i_; +text: .text%__1cFParseMprofile_call6MpnENode__v_; +text: .text%__1cFciEnvbTget_instance_klass_for_declared_method_holder6FpnHciKlass__pnPciInstanceKlass__; +text: .text%__1cIGraphKitWround_double_arguments6MpnIciMethod__v_; +text: .text%__1cIGraphKitTround_double_result6MpnIciMethod__v_; +text: .text%__1cFParseHdo_call6M_v_; +text: .text%__1cNloadConP0NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cHMulNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cMPhaseIterGVNJtransform6MpnENode__2_; +text: .text%__1cHTypeIntFwiden6kMpknEType__3_; +text: .text%__1cSsafePoint_pollNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJloadSNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKarrayKlassLobject_size6kMi_i_; +text: .text%__1cKMemBarNodeEhash6kM_I_; +text: .text%__1cQSystemDictionaryPresolve_or_null6FnMsymbolHandle_nGHandle_2pnGThread__pnMklassOopDesc__; +text: .text%__1cNinstanceKlassKjava_super6kM_pnMklassOopDesc__: instanceKlass.o; +text: .text%__1cMLinkResolverVresolve_invokevirtual6FrnICallInfo_nGHandle_nSconstantPoolHandle_ipnGThread__v_; +text: .text%__1cKMemoryPoolYrecord_peak_memory_usage6M_v_; +text: .text%__1cMURShiftLNodeGOpcode6kM_i_; +text: .text%__1cIGraphKitUmake_exception_state6MpnENode__pnNSafePointNode__; +text: .text%__1cLProfileDataOtranslate_from6Mp0_v_: ciMethodData.o; +text: .text%__1cRsarI_reg_imm5NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cLBuildCutout2t6MpnIGraphKit_pnENode_ff_v_; +text: .text%__1cTCompareAndSwapLNodeGOpcode6kM_i_; +text: .text%__1cQxorI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMMergeMemNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLLShiftINodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cNflagsRegLOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cQsubI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKarrayKlassGvtable6kM_pnLklassVtable__; +text: .text%__1cRshrI_reg_imm5NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQCallLeafNoFPNodeGOpcode6kM_i_; +text: .text%__1cMURShiftINodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cFStateM_sub_Op_ConP6MpknENode__v_; +text: .text%__1cIGraphKitMsaved_ex_oop6FpnNSafePointNode__pnENode__; +text: .text%__1cISubINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cPciInstanceKlassFsuper6M_p0_; +text: .text%__1cIBoolNodeHsize_of6kM_I_; +text: .text%__1cSobjArrayKlassKlassIoop_size6kMpnHoopDesc__i_: objArrayKlassKlass.o; +text: .text%__1cPcompP_iRegPNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cJloadPNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cPBytecode_invokeJsignature6kM_pnNsymbolOopDesc__; +text: .text%__1cFframebGinterpreter_callee_receiver_addr6MnMsymbolHandle__ppnHoopDesc__; +text: .text%__1cNSignatureInfoGdo_int6M_v_: bytecode.o; +text: .text%__1cOstackSlotLOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cKInlineTreeMok_to_inline6MpnIciMethod_pnIJVMState_rnNciCallProfile_pnMWarmCallInfo__8_; +text: .text%__1cOGenerateOopMapbAget_basic_block_containing6kMi_pnKBasicBlock__; +text: .text%__1cICodeHeapSallocated_capacity6kM_I_; +text: .text%__1cICHeapObj2n6FI_pv_; +text: .text%__1cQsubL_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cWCallLeafNoFPDirectNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cFTypeDEhash6kM_i_; +text: .text%__1cKTypeRawPtrHget_con6kM_i_; +text: .text%__1cJStartNodeFmatch6MpknIProjNode_pknHMatcher__pnENode__; +text: .text%jni_ExceptionOccurred: jni.o; +text: .text%__1cKciTypeFlowLStateVectorStype_meet_internal6FpnGciType_3p0_3_; +text: .text%__1cMloadConINodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cGIfNodeHsize_of6kM_I_: classes.o; +text: .text%__1cPconvL2I_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIimmLOperJconstantL6kM_x_: ad_sparc_clone.o; +text: .text%__1cTStackWalkCompPolicyRcompilation_level6MnMmethodHandle_i_i_; +text: .text%jni_GetByteArrayRegion: jni.o; +text: .text%__1cIGraphKitTset_all_memory_call6MpnENode__v_; +text: .text%__1cSHighResTimeSamplerLtake_sample6M_x_: statSampler.o; +text: .text%__1cHCompileFstart6kM_pnJStartNode__; +text: .text%__1cPStatSamplerTaskEtask6M_v_: statSampler.o; +text: .text%__1cMPeriodicTaskOreal_time_tick6FI_v_; +text: .text%__1cQPlaceholderTableKfind_entry6MiInMsymbolHandle_nGHandle__pnNsymbolOopDesc__; +text: .text%__1cIParmNodeJideal_reg6kM_I_; +text: .text%__1cQandL_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIMachNodeRget_base_and_disp6kMrirpknHTypePtr__pknENode__; +text: .text%__1cQSystemDictionarybBresolve_array_class_or_null6FnMsymbolHandle_nGHandle_2pnGThread__pnMklassOopDesc__; +text: .text%__1cIregFOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cRbranchLoopEndNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cGRFrame2t6MnFframe_pnKJavaThread_kp0_v_; +text: .text%jni_GetArrayLength: jni.o; +text: .text%__1cPciInstanceKlassUget_canonical_holder6Mi_p0_; +text: .text%__1cJloadLNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOClearArrayNodeGOpcode6kM_i_; +text: .text%__1cPClassFileParserbDverify_legal_method_signature6MnMsymbolHandle_1pnGThread__i_; +text: .text%__1cVCompressedWriteStreamEgrow6M_v_; +text: .text%JVM_Write; +text: .text%__1cLciSignature2t6MpnHciKlass_pnIciSymbol__v_; +text: .text%__1cIciMethod2t6MnMmethodHandle__v_; +text: .text%__1cIHaltNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cWShouldNotReachHereNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLOpaque1NodeGOpcode6kM_i_; +text: .text%__1cSbranchCon_longNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKstoreCNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cHAddNodePadd_of_identity6kMpknEType_3_3_; +text: .text%__1cUcompU_iReg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%JVM_RawMonitorEnter; +text: .text%JVM_RawMonitorExit; +text: .text%__1cOMachReturnNodeKin_RegMask6kMI_rknHRegMask__; +text: .text%__1cMTypeKlassPtrKadd_offset6kMi_pknHTypePtr__; +text: .text%__1cWShouldNotReachHereNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPcmpFastLockNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cETypeRget_typeflow_type6FpnGciType__pk0_; +text: .text%__1cOJNIHandleBlockNrelease_block6Fp0pnGThread__v_; +text: .text%__1cRcmpFastUnlockNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cXinitialize_static_field6FpnPfieldDescriptor_pnGThread__v_: classFileParser.o; +text: .text%__1cURethrowExceptionNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOJNIHandleBlockOallocate_block6FpnGThread__p0_; +text: .text%__1cNSignatureInfoHdo_bool6M_v_: bytecode.o; +text: .text%__1cKBufferBlobHoops_do6MpnKOopClosure__v_: codeBlob.o; +text: .text%__1cSandI_reg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIAddINodeIadd_ring6kMpknEType_3_3_; +text: .text%__1cLTypeInstPtrQcast_to_ptr_type6kMnHTypePtrDPTR__pknEType__; +text: .text%__1cMloadConLNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cFParseFmerge6Mi_v_; +text: .text%__1cNSafePointNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cJTypeTupleFxdual6kM_pknEType__; +text: .text%__1cNLoadKlassNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cPorI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cLRethrowNodeGOpcode6kM_i_; +text: .text%__1cJloadSNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cICodeHeapIcapacity6kM_I_; +text: .text%__1cKMemoryPoolImax_size6kM_I_: memoryPool.o; +text: .text%__1cMCodeHeapPoolNused_in_bytes6M_I_: memoryPool.o; +text: .text%__1cPcmpFastLockNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cMCodeHeapPoolQget_memory_usage6M_nLMemoryUsage__; +text: .text%__1cFArena2T6M_v_; +text: .text%__1cKMemBarNodeFmatch6MpknIProjNode_pknHMatcher__pnENode__; +text: .text%__1cOCallRelocationFvalue6M_pC_: relocInfo.o; +text: .text%__1cHoopDescSslow_identity_hash6M_i_; +text: .text%__1cSObjectSynchronizerXidentity_hash_value_for6FnGHandle__i_; +text: .text%__1cLPCTableNodeEhash6kM_I_; +text: .text%__1cHConNodeLout_RegMask6kM_rknHRegMask__: classes.o; +text: .text%__1cXPhaseAggressiveCoalesceYinsert_copy_with_overlap6MpnFBlock_pnENode_II_v_; +text: .text%__1cOloadConI13NodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cJloadBNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cMtlsLoadPNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMPhaseChaitinNFind_compress6MI_I_; +text: .text%__1cMindIndexOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cFStateN_sub_Op_LoadP6MpknENode__v_; +text: .text%__1cFframeVinterpreter_frame_bci6kM_i_; +text: .text%__1cNGCTaskManagerIget_task6MI_pnGGCTask__; +text: .text%__1cLGCTaskQdDueueGremove6M_pnGGCTask__; +text: .text%__1cLGCTaskQdDueueHenqueue6MpnGGCTask__v_; +text: .text%__1cNGCTaskManagerPnote_completion6MI_v_; +text: .text%__1cQandI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIGraphKitHjava_bc6kM_nJBytecodesECode__; +text: .text%__1cIGraphKitNbuiltin_throw6MnODeoptimizationLDeoptReason_pnENode__v_; +text: .text%__1cOGenerateOopMapHget_var6Mi_nNCellTypeState__; +text: .text%__1cRinterpretedVFrameGmethod6kM_pnNmethodOopDesc__; +text: .text%jni_GetSuperclass: jni.o; +text: .text%__1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_; +text: .text%__1cCosUos_exception_wrapper6FpFpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v2468_v_; +text: .text%__1cTAbstractInterpreterbFsize_top_interpreter_activation6FpnNmethodOopDesc__i_; +text: .text%__1cIMulINodeGOpcode6kM_i_; +text: .text%__1cRcompL_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cNloadKlassNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cJloadPNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cGGCTask2t6M_v_; +text: .text%__1cJloadSNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cIJumpDataKcell_count6M_i_: ciMethodData.o; +text: .text%__1cObranchConPNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cITypeFuncFxdual6kM_pknEType__; +text: .text%__1cQjava_lang_StringGlength6FpnHoopDesc__i_; +text: .text%__1cFStateM_sub_Op_CmpI6MpknENode__v_; +text: .text%__1cJcmpOpOperFccode6kM_i_: ad_sparc_clone.o; +text: .text%__1cGciType2t6MnLKlassHandle__v_; +text: .text%__1cHciKlass2t6MnLKlassHandle__v_; +text: .text%__1cMindirectOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cSPSPromotionManagerbBgc_thread_promotion_manager6Fi_p0_; +text: .text%__1cQxorI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJloadLNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cIregFOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cKcmpOpPOperFccode6kM_i_: ad_sparc_clone.o; +text: .text%__1cNloadKlassNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cHPhiNodeMslice_memory6kMpknHTypePtr__p0_; +text: .text%__1cPCheckCastPPNodeJideal_reg6kM_I_: connode.o; +text: .text%__1cObranchConPNodeJlabel_set6MrnFLabel_I_v_; +text: .text%__1cObranchConPNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cICHeapObj2k6Fpv_v_; +text: .text%__1cSaddL_reg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cRmethodDataOopDescJbci_to_dp6Mi_pC_; +text: .text%__1cMloadConFNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cRInvocationCounterJset_carry6M_v_; +text: .text%__1cFArena2t6M_v_; +text: .text%__1cRInterpreterOopMapLiterate_oop6MpnNOffsetClosure__v_; +text: .text%__1cRInterpreterOopMap2T6M_v_; +text: .text%__1cLOopMapCacheGlookup6MnMmethodHandle_ipnRInterpreterOopMap__v_; +text: .text%__1cNinstanceKlassImask_for6MnMmethodHandle_ipnRInterpreterOopMap__v_; +text: .text%__1cNmethodOopDescImask_for6MipnRInterpreterOopMap__v_; +text: .text%__1cRInterpreterOopMap2t6M_v_; +text: .text%__1cISubINodeDsub6kMpknEType_3_3_; +text: .text%__1cFParseOreturn_current6MpnENode__v_; +text: .text%__1cRsarI_reg_imm5NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMMonitorValueIwrite_on6MpnUDebugInfoWriteStream__v_; +text: .text%__1cMloadConLNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJStoreNodeSIdeal_masked_input6MpnIPhaseGVN_I_pnENode__; +text: .text%jni_GetPrimitiveArrayCritical: jni.o; +text: .text%jni_ReleasePrimitiveArrayCritical: jni.o; +text: .text%__1cPconvI2L_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cNMemoryServiceXtrack_memory_pool_usage6FpnKMemoryPool__v_; +text: .text%__1cSmembar_releaseNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJimmU5OperIconstant6kM_i_: ad_sparc_clone.o; +text: .text%__1cPciInstanceKlass2t6MnLKlassHandle__v_; +text: .text%__1cLOpaque1NodeEhash6kM_I_; +text: .text%__1cJStoreNodeZIdeal_sign_extended_input6MpnIPhaseGVN_i_pnENode__; +text: .text%__1cSbranchCon_longNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cOGenerateOopMapGppload6MpnNCellTypeState_i_v_; +text: .text%__1cSmembar_releaseNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cNbranchConNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cFciEnvVnotice_inlined_method6MpnIciMethod__v_; +text: .text%__1cFKlassTarray_klass_or_null6Mi_pnMklassOopDesc__; +text: .text%__1cZCallDynamicJavaDirectNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJMultiNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKStoreLNodeGOpcode6kM_i_; +text: .text%__1cbBopt_virtual_call_RelocationEtype6M_nJrelocInfoJrelocType__: relocInfo.o; +text: .text%__1cTconstantPoolOopDescbCklass_ref_at_if_loaded_check6FnSconstantPoolHandle_ipnGThread__pnMklassOopDesc__; +text: .text%__1cHciField2t6MpnPciInstanceKlass_i_v_; +text: .text%__1cNloadKlassNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOJNIHandleBlockHoops_do6MpnKOopClosure__v_; +text: .text%__1cOGenerateOopMapJdo_method6Miiii_v_; +text: .text%__1cRsarI_reg_imm5NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRbranchLoopEndNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cQmulL_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cLstoreP0NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cLRethrowNodeKmatch_edge6kMI_I_; +text: .text%__1cFTypeFEhash6kM_i_; +text: .text%__1cHnmethodHoops_do6MpnKOopClosure__v_; +text: .text%__1cFStateM_sub_Op_AddI6MpknENode__v_; +text: .text%__1cOParseGeneratorIgenerate6MpnIJVMState__2_; +text: .text%__1cFParseQcreate_entry_map6M_pnNSafePointNode__; +text: .text%__1cFArenaEused6kM_I_; +text: .text%__1cFParseLbuild_exits6M_v_; +text: .text%__1cFParseIdo_exits6M_v_; +text: .text%__1cFParse2t6MpnIJVMState_pnIciMethod_f_v_; +text: .text%__1cIBoolNodeDcmp6kMrknENode__I_; +text: .text%__1cFParsePdo_method_entry6M_v_; +text: .text%__1cNCallGeneratorKfor_inline6FpnIciMethod_f_p0_; +text: .text%__1cbGJvmtiVMObjectAllocEventCollector2t6M_v_; +text: .text%__1cbGJvmtiVMObjectAllocEventCollector2T6M_v_; +text: .text%__1cQconstMethodKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cRciVirtualCallDataOtranslate_from6MpnLProfileData__v_; +text: .text%jni_IsSameObject: jni.o; +text: .text%__1cMloadConINodeIpipeline6kM_pknIPipeline__; +text: .text%__1cNbranchConNodeJlabel_set6MrnFLabel_I_v_; +text: .text%__1cNbranchConNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQandL_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cLmethodKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cLsymbolKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cIciObjectFklass6M_pnHciKlass__; +text: .text%__1cLSymbolTableFprobe6Fpkci_pnNsymbolOopDesc__; +text: .text%__1cPThreadLocalNodeGOpcode6kM_i_; +text: .text%__1cZPhaseConservativeCoalesceKupdate_ifg6MIIpnIIndexSet_2_v_; +text: .text%__1cZPhaseConservativeCoalesceMunion_helper6MpnENode_2II222pnFBlock_I_v_; +text: .text%__1cOMethodLivenessKBasicBlockJstore_one6Mi_v_; +text: .text%__1cIIndexSetEswap6Mp0_v_; +text: .text%__1cHTypeAryEmake6FpknEType_pknHTypeInt__pk0_; +text: .text%__1cPClassFileParserbCverify_legal_class_modifiers6MipnGThread__v_; +text: .text%__1cKTypeAryPtrFxdual6kM_pknEType__; +text: .text%__1cLAccessFlagsPatomic_set_bits6Mi_v_; +text: .text%__1cQComputeCallStackJdo_object6Mii_v_: generateOopMap.o; +text: .text%__1cNinstanceKlassWcompute_modifier_flags6kMpnGThread__i_; +text: .text%__1cKstoreBNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cKCastPPNodeQIdeal_DU_postCCP6MpnIPhaseCCP__pnENode__; +text: .text%__1cKstorePNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cOPhaseIdealLoopOsplit_thru_phi6MpnENode_2i_2_; +text: .text%__1cENodeGOpcode6kM_i_; +text: .text%__1cRshrP_reg_imm5NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQandI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIciMethodbBinterpreter_call_site_count6Mi_i_; +text: .text%__1cGBitMapIset_from6M0_v_; +text: .text%__1cNCompileBrokerOcompile_method6FnMmethodHandle_i1ipkcpnGThread__pnHnmethod__; +text: .text%__1cTconstantPoolOopDescbDresolve_string_constants_impl6FnSconstantPoolHandle_pnGThread__v_; +text: .text%__1cHSubNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cFChunk2n6FII_pv_; +text: .text%__1cTCallDynamicJavaNodeGOpcode6kM_i_; +text: .text%__1cKstoreBNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cILoadNodeDcmp6kMrknENode__I_; +text: .text%__1cIciObject2t6M_v_; +text: .text%__1cSconstMethodOopDescZchecked_exceptions_length6kM_i_; +text: .text%__1cRcompL_reg_conNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cHCompileXin_preserve_stack_slots6M_I_; +text: .text%__1cPciObjectFactoryUget_empty_methodData6M_pnMciMethodData__; +text: .text%__1cMciMethodData2t6M_v_; +text: .text%__1cHOrINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cFframeLreal_sender6kMpnLRegisterMap__0_; +text: .text%__1cGRFrameGcaller6M_p0_; +text: .text%__1cPCheckCastPPNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cRshrP_reg_imm5NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cJJavaCallsEcall6FpnJJavaValue_nMmethodHandle_pnRJavaCallArguments_pnGThread__v_; +text: .text%__1cXmembar_release_lockNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cJloadINodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cXJNI_ArgumentPusherVaArgKget_object6M_v_: jni.o; +text: .text%__1cMloadConFNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cIMulINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cMCreateExNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cQaddL_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMCreateExNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cISubINodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cFKlassQset_next_sibling6MpnMklassOopDesc__v_; +text: .text%__1cQdivD_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cNCatchProjNodeDcmp6kMrknENode__I_; +text: .text%__1cKTypeOopPtrEhash6kM_i_; +text: .text%__1cIMinINodeGOpcode6kM_i_; +text: .text%__1cMURShiftINodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cFframeRoops_code_blob_do6MpnKOopClosure_pknLRegisterMap__v_; +text: .text%__1cKTypeRawPtrFxmeet6kMpknEType__3_; +text: .text%JVM_GetMethodIxModifiers; +text: .text%__1cIMulLNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cPconvI2L_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLLShiftINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cTCreateExceptionNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%JVM_IsInterface; +text: .text%__1cPorI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cIDivINodeGOpcode6kM_i_; +text: .text%__1cOGenerateOopMapTmerge_state_into_bb6MpnKBasicBlock__v_; +text: .text%__1cICodeHeapIallocate6MI_pv_; +text: .text%__1cICodeHeapPsearch_freelist6MI_pnJFreeBlock__; +text: .text%__1cLOpaque1NodeLbottom_type6kM_pknEType__: connode.o; +text: .text%__1cNloadRangeNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cLRShiftLNodeGOpcode6kM_i_; +text: .text%__1cJCodeCacheIallocate6Fi_pnICodeBlob__; +text: .text%__1cSCountedLoopEndNodeKstride_con6kM_i_; +text: .text%__1cUPipeline_Use_Element2t6M_v_: output.o; +text: .text%__1cRshrL_reg_imm6NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cHCompileSregister_intrinsic6MpnNCallGenerator__v_; +text: .text%__1cNSCMemProjNodeGOpcode6kM_i_; +text: .text%__1cNimmP_pollOperEtype6kM_pknEType__: ad_sparc_clone.o; +text: .text%__1cRloadConP_pollNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cQinstanceRefKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cQinstanceRefKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cOGenerateOopMapUreachable_basicblock6Fp0ipi_v_; +text: .text%__1cPciInstanceKlassLfind_method6MpnIciSymbol_2_pnIciMethod__; +text: .text%__1cXvirtual_call_RelocationLunpack_data6M_v_; +text: .text%__1cFciEnvRfind_system_klass6MpnIciSymbol__pnHciKlass__; +text: .text%__1cLRegisterMapIpd_clear6M_v_; +text: .text%__1cHUNICODEHas_utf86FpHi_pc_; +text: .text%__1cLstoreP0NodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cParrayKlassKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cParrayKlassKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cIGraphKitYcombine_exception_states6MpnNSafePointNode_2_v_; +text: .text%__1cQmulL_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRshrP_reg_imm5NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSconstMethodOopDescYchecked_exceptions_start6kM_pnXCheckedExceptionElement__; +text: .text%__1cPClassFileParserYparse_checked_exceptions6MpHInSconstantPoolHandle_pnGThread__1_; +text: .text%__1cKstoreLNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cRbranchLoopEndNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQConstantIntValueIwrite_on6MpnUDebugInfoWriteStream__v_; +text: .text%__1cSconvI2D_helperNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cPClassFileStreamHskip_u26MipnGThread__v_; +text: .text%__1cUcompI_iReg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOMacroAssemblerNverify_thread6M_v_; +text: .text%__1cIGraphKitZset_results_for_java_call6MpnMCallJavaNode__pnENode__; +text: .text%__1cSbranchCon_longNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cHnmethodVcleanup_inline_caches6M_v_; +text: .text%__1cTciConstantPoolCacheGinsert6Mipv_v_; +text: .text%__1cIAddLNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cFStateO_sub_Op_StoreI6MpknENode__v_; +text: .text%__1cKHandleAreaHoops_do6MpnKOopClosure__v_; +text: .text%__1cHciField2t6MpnPfieldDescriptor__v_; +text: .text%__1cRSignatureIterator2t6MpnGThread_pnNsymbolOopDesc__v_; +text: .text%__1cMloadConLNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cYcompareAndSwapL_boolNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cFKlassMnext_sibling6kM_p0_; +text: .text%__1cKDictionaryStry_get_next_class6M_pnMklassOopDesc__; +text: .text%__1cNinstanceKlassKmethods_do6MpFpnNmethodOopDesc__v_v_; +text: .text%__1cQSystemDictionaryStry_get_next_class6F_pnMklassOopDesc__; +text: .text%__1cSobjArrayKlassKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cSobjArrayKlassKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%__1cJimmU5OperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cLBlock_ArrayEgrow6MI_v_; +text: .text%__1cYinternal_word_RelocationLunpack_data6M_v_; +text: .text%__1cKcmpOpPOperGnegate6M_v_: ad_sparc_clone.o; +text: .text%__1cObranchConPNodeGnegate6M_v_: ad_sparc_misc.o; +text: .text%__1cUvisit_all_interfaces6FpnPobjArrayOopDesc_pnXInterfaceVisiterClosure__v_; +text: .text%__1cLBoxLockNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPcmpFastLockNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cHRetNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cPconvL2I_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKoopFactoryTnew_system_objArray6FipnGThread__pnPobjArrayOopDesc__; +text: .text%__1cbDcatch_cleanup_find_cloned_def6FpnFBlock_pnENode_1rnLBlock_Array_i_3_: lcm.o; +text: .text%__1cQxorI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cKstoreLNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cFciEnvVget_constant_by_index6MpnPciInstanceKlass_i_nKciConstant__; +text: .text%__1cFciEnvbAget_constant_by_index_impl6MpnPciInstanceKlass_i_nKciConstant__; +text: .text%__1cOClearArrayNodeKmatch_edge6kMI_I_; +text: .text%__1cPconvL2I_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cJloadSNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKJavaThreadHoops_do6MpnKOopClosure__v_; +text: .text%__1cSFixupMirrorClosureJdo_object6MpnHoopDesc__v_: universe.o; +text: .text%__1cFStateP_sub_Op_LShiftI6MpknENode__v_; +text: .text%__1cQandL_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPSignatureStreamRas_symbol_or_null6M_pnNsymbolOopDesc__; +text: .text%__1cKoopFactoryYnew_permanent_shortArray6FipnGThread__pnQtypeArrayOopDesc__; +text: .text%__1cIGraphKitbBset_arguments_for_java_call6MpnMCallJavaNode__v_; +text: .text%__1cIGraphKitJpush_node6MnJBasicType_pnENode__v_: callGenerator.o; +text: .text%__1cNSignatureInfoIdo_array6Mii_v_: bytecode.o; +text: .text%__1cJcmpOpOperGnegate6M_v_: ad_sparc_clone.o; +text: .text%__1cMloadConPNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%jni_SetObjectArrayElement: jni.o; +text: .text%__1cSandI_reg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cPThreadLocalNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cNSafePointNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cObranchConUNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRshlL_reg_imm6NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cQandI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSandI_reg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cRCardTableModRefBSPdirty_MemRegion6MnJMemRegion__v_; +text: .text%__1cZresource_reallocate_bytes6FpcII_0_; +text: .text%__1cLConvL2INodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cOAbstractICacheQinvalidate_range6FpCi_v_; +text: .text%__1cKstorePNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cIMaxINodeGOpcode6kM_i_; +text: .text%__1cTDirectCallGeneratorIgenerate6MpnIJVMState__2_; +text: .text%__1cNCallGeneratorPfor_direct_call6FpnIciMethod__p0_; +text: .text%__1cMWarmCallInfoLalways_cold6F_p0_; +text: .text%__1cIimmDOperJconstantD6kM_d_: ad_sparc_clone.o; +text: .text%__1cIPhaseIFGEinit6MI_v_; +text: .text%__1cJPhaseLiveHcompute6MI_v_; +text: .text%__1cMLinkResolverbCresolve_virtual_call_or_null6FnLKlassHandle_1nMsymbolHandle_21_nMmethodHandle__; +text: .text%__1cSaddI_reg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cJloadLNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cFTypeDEmake6Fd_pk0_; +text: .text%__1cPThreadRootsTaskEname6M_pc_: psTasks.o; +text: .text%__1cPThreadRootsTaskFdo_it6MpnNGCTaskManager_I_v_; +text: .text%__1cRshlI_reg_imm5NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQaddL_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMloadConDNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cFStateN_sub_Op_LoadI6MpknENode__v_; +text: .text%__1cIMachOperEtype6kM_pknEType__; +text: .text%JVM_GetCPClassNameUTF; +text: .text%__1cKBufferBlobGcreate6Fpkci_p0_; +text: .text%__1cKcmpOpUOperFccode6kM_i_: ad_sparc_clone.o; +text: .text%__1cObranchConUNodeJlabel_set6MrnFLabel_I_v_; +text: .text%__1cObranchConUNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%jni_GetStringLength: jni.o; +text: .text%__1cMLinkResolverbBresolve_static_call_or_null6FnLKlassHandle_nMsymbolHandle_21_nMmethodHandle__; +text: .text%__1cLConvI2LNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cJloadPNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cMoutputStream2t6Mi_v_; +text: .text%__1cMstringStreamJas_string6M_pc_; +text: .text%__1cMstringStream2T6M_v_; +text: .text%__1cMstringStream2t6MI_v_; +text: .text%__1cIGraphKitMreset_memory6M_pnENode__; +text: .text%__1cZCallDynamicJavaDirectNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKstorePNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cENodeMsetup_is_top6M_v_; +text: .text%__1cIGotoNodeGOpcode6kM_i_; +text: .text%__1cPfieldDescriptorRint_initial_value6kM_i_; +text: .text%__1cNbranchConNodeGnegate6M_v_: ad_sparc_misc.o; +text: .text%__1cOGenerateOopMapLbb_mark_fct6Fp0ipi_v_; +text: .text%__1cKcmpOpPOperFequal6kM_i_: ad_sparc_clone.o; +text: .text%__1cSInterpreterRuntimeE_new6FpnKJavaThread_pnTconstantPoolOopDesc_i_v_; +text: .text%__1cKReturnNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cOGenerateOopMapRsigchar_to_effect6McipnNCellTypeState__2_; +text: .text%__1cOGenerateOopMapIdo_field6Miiii_v_; +text: .text%__1cJloadINodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSmembar_releaseNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cSaddL_reg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cLRShiftINodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cEDict2t6MpFpkv2_ipF2_i_v_; +text: .text%__1cEDict2T6M_v_; +text: .text%__1cKBranchDataPpost_initialize6MpnOBytecodeStream_pnRmethodDataOopDesc__v_; +text: .text%__1cLOopRecorder2t6MpnFArena__v_; +text: .text%__1cRClassPathZipEntryLopen_stream6Mpkc_pnPClassFileStream__; +text: .text%__1cMLinkResolverbCresolve_special_call_or_null6FnLKlassHandle_nMsymbolHandle_21_nMmethodHandle__; +text: .text%__1cIModINodeGOpcode6kM_i_; +text: .text%__1cRInterpretedRFrame2t6MnFframe_pnKJavaThread_nMmethodHandle__v_; +text: .text%__1cKJavaThreadQlast_java_vframe6MpnLRegisterMap__pnKjavaVFrame__; +text: .text%__1cTStackWalkCompPolicyVfindTopInlinableFrame6MpnNGrowableArray4CpnGRFrame____2_; +text: .text%__1cTStackWalkCompPolicyXmethod_invocation_event6MnMmethodHandle_pnGThread__v_; +text: .text%__1cISubLNodeGOpcode6kM_i_; +text: .text%__1cKciTypeFlow2t6MpnFciEnv_pnIciMethod_i_v_; +text: .text%__1cKciTypeFlowPget_start_state6M_pkn0ALStateVector__; +text: .text%__1cKciTypeFlowHdo_flow6M_v_; +text: .text%__1cKciTypeFlowKflow_types6M_v_; +text: .text%__1cKciTypeFlowKmap_blocks6M_v_; +text: .text%__1cMloadConPNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cTconstantPoolOopDescbCverify_constant_pool_resolve6FnSconstantPoolHandle_nLKlassHandle_pnGThread__v_; +text: .text%__1cIciMethodJload_code6M_v_; +text: .text%__1cMciMethodDataJload_data6M_v_; +text: .text%__1cIGraphKitTuse_exception_state6MpnNSafePointNode__pnENode__; +text: .text%__1cOcompU_iRegNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIGraphKitGmemory6MI_pnENode__; +text: .text%__1cIHaltNodeEhash6kM_I_: classes.o; +text: .text%__1cFKlassQup_cast_abstract6M_p0_; +text: .text%__1cKReturnNodeEhash6kM_I_: classes.o; +text: .text%__1cPClassFileParserXverify_legal_class_name6MnMsymbolHandle_pnGThread__v_; +text: .text%__1cPjava_lang_ClassNcreate_mirror6FnLKlassHandle_pnGThread__pnHoopDesc__; +text: .text%__1cIAndINodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cMciMethodData2t6MnQmethodDataHandle__v_; +text: .text%__1cIAndINodeImul_ring6kMpknEType_3_3_; +text: .text%__1cLOpaque2NodeGOpcode6kM_i_; +text: .text%__1cOClearArrayNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cNmethodOopDescbEfast_exception_handler_bci_for6MnLKlassHandle_ipnGThread__i_; +text: .text%__1cSInterpreterRuntimebFexception_handler_for_exception6FpnKJavaThread_pnHoopDesc__pC_; +text: .text%__1cOPhaseIdealLoopPis_counted_loop6MpnENode_pnNIdealLoopTree__2_; +text: .text%__1cQComputeCallStackHdo_void6M_v_: generateOopMap.o; +text: .text%__1cFKlassRinitialize_supers6MpnMklassOopDesc_pnGThread__v_; +text: .text%__1cKKlass_vtbl2n6FIrnLKlassHandle_ipnGThread__pv_; +text: .text%__1cFKlassVbase_create_klass_oop6FrnLKlassHandle_irknKKlass_vtbl_pnGThread__pnMklassOopDesc__; +text: .text%__1cQjava_lang_StringLutf8_length6FpnHoopDesc__i_; +text: .text%jni_GetStringUTFLength: jni.o; +text: .text%__1cQjava_lang_StringOas_utf8_string6FpnHoopDesc_ii_pc_; +text: .text%jni_GetStringUTFRegion: jni.o; +text: .text%__1cFKlassRbase_create_klass6FrnLKlassHandle_irknKKlass_vtbl_pnGThread__1_; +text: .text%__1cHUNICODELutf8_length6FpHi_i_; +text: .text%__1cQPlaceholderTableMremove_entry6MiInMsymbolHandle_nGHandle__v_; +text: .text%__1cKstoreBNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKstoreINodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cQSystemDictionaryTload_instance_class6FnMsymbolHandle_nGHandle_pnGThread__nTinstanceKlassHandle__; +text: .text%__1cRsarI_reg_imm5NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cUcompU_iReg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cQmulL_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cHAddNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cUcompU_iReg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKPerfStringKset_string6Mpkc_v_; +text: .text%__1cQjava_lang_StringRas_unicode_string6FpnHoopDesc_ri_pH_; +text: .text%JVM_InternString; +text: .text%__1cLStringTableGintern6FpnHoopDesc_pnGThread__2_; +text: .text%__1cCosGrandom6F_l_; +text: .text%__1cKimmP13OperIconstant6kM_i_: ad_sparc_clone.o; +text: .text%__1cVcompP_iRegP_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cKoopFactoryXnew_permanent_byteArray6FipnGThread__pnQtypeArrayOopDesc__; +text: .text%__1cRcompL_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cRMachNullCheckNodeLout_RegMask6kM_rknHRegMask__: machnode.o; +text: .text%__1cSTailCalljmpIndNodeNis_block_proj6kM_pknENode__: ad_sparc_misc.o; +text: .text%__1cIGraphKitPpush_pair_local6Mi_v_: parse2.o; +text: .text%__1cICodeHeapKdeallocate6Mpv_v_; +text: .text%__1cJCodeCacheEfree6FpnICodeBlob__v_; +text: .text%__1cKTypeRawPtrEmake6FpC_pk0_; +text: .text%jni_SetIntField: jni.o; +text: .text%__1cNIdealLoopTreeMcounted_loop6MpnOPhaseIdealLoop__v_; +text: .text%__1cKBufferBlobEfree6Fp0_v_; +text: .text%__1cPconvL2I_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPciObjectFactoryMvm_symbol_at6Fi_pnIciSymbol__; +text: .text%__1cKDictionaryJadd_klass6MnMsymbolHandle_nGHandle_nLKlassHandle__v_; +text: .text%__1cVshrL_reg_imm6_L2INodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cZCallDynamicJavaDirectNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cIGraphKitTcreate_and_xform_if6MpnENode_2ff_pnGIfNode__: graphKit.o; +text: .text%__1cWImplicitExceptionTableGappend6MII_v_; +text: .text%__1cRMachNullCheckNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cLProfileDataPpost_initialize6MpnOBytecodeStream_pnRmethodDataOopDesc__v_: ciMethodData.o; +text: .text%__1cQxorI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNIdealLoopTreeVadjust_loop_exit_prob6MpnOPhaseIdealLoop__v_; +text: .text%__1cNinstanceKlassVadd_dependent_nmethod6MpnHnmethod__v_; +text: .text%__1cSandI_reg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cIPhaseIFGISquareUp6M_v_; +text: .text%__1cLklassVtableMget_mirandas6FpnNGrowableArray4CpnNmethodOopDesc___pnMklassOopDesc_pnPobjArrayOopDesc_8_v_; +text: .text%__1cKCodeBuffer2T6M_v_; +text: .text%__1cQPSGenerationPoolQget_memory_usage6M_nLMemoryUsage__; +text: .text%__1cLOpaque1NodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cMURShiftINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cRcompL_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cXAdaptiveWeightedAverageGsample6Mf_v_; +text: .text%__1cFKlassWappend_to_sibling_list6M_v_; +text: .text%__1cQSystemDictionarySjava_system_loader6F_pnHoopDesc__; +text: .text%__1cFKlassMset_subklass6MpnMklassOopDesc__v_; +text: .text%__1cOGenerateOopMapLmerge_state6Fp0ipi_v_; +text: .text%__1cMTypeKlassPtrFxdual6kM_pknEType__; +text: .text%__1cQSystemDictionaryVdefine_instance_class6FnTinstanceKlassHandle_pnGThread__v_; +text: .text%__1cSinstanceKlassKlassXallocate_instance_klass6MiiiinNReferenceType_pnGThread__pnMklassOopDesc__; +text: .text%__1cPClassFileParserbBcheck_final_method_override6FnTinstanceKlassHandle_pnGThread__v_; +text: .text%__1cJCodeCachebKnumber_of_nmethods_with_dependencies6F_i_; +text: .text%__1cNinstanceKlassQinit_implementor6M_v_; +text: .text%__1cPClassFileStream2t6MpCipc_v_; +text: .text%__1cNinstanceKlassSprocess_interfaces6MpnGThread__v_; +text: .text%__1cNinstanceKlassYcompute_secondary_supers6MipnGThread__pnPobjArrayOopDesc__; +text: .text%__1cKoopFactoryRnew_instanceKlass6FiiiinNReferenceType_pnGThread__pnMklassOopDesc__; +text: .text%__1cNinstanceKlassWdo_local_static_fields6MpFpnPfieldDescriptor_pnGThread__v4_v_; +text: .text%__1cPClassFileParserMsort_methods6MnOobjArrayHandle_111pnGThread__nPtypeArrayHandle__; +text: .text%__1cFKlassKsuperklass6kM_pnNinstanceKlass__; +text: .text%__1cPClassFileParserbBparse_constant_pool_entries6MnSconstantPoolHandle_ipnGThread__v_; +text: .text%__1cPClassFileParserTparse_constant_pool6MpnGThread__nSconstantPoolHandle__; +text: .text%__1cPClassFileParserbDcompute_transitive_interfaces6MnTinstanceKlassHandle_nOobjArrayHandle_pnGThread__2_; +text: .text%__1cIUniverseTflush_dependents_on6FnTinstanceKlassHandle__v_; +text: .text%__1cLklassItableZsetup_itable_offset_table6FnTinstanceKlassHandle__v_; +text: .text%__1cPClassFileParserbCcheck_super_interface_access6FnTinstanceKlassHandle_pnGThread__v_; +text: .text%__1cNinstanceKlassQeager_initialize6MpnGThread__v_; +text: .text%__1cPClassFileParserVset_precomputed_flags6MnTinstanceKlassHandle__v_; +text: .text%__1cPClassFileParserbAparse_classfile_attributes6MnSconstantPoolHandle_nTinstanceKlassHandle_pnGThread__v_; +text: .text%__1cKcmpOpPOperJnot_equal6kM_i_: ad_sparc_clone.o; +text: .text%__1cMPhaseIterGVNIoptimize6M_v_; +text: .text%__1cOPhaseTransform2t6MnFPhaseLPhaseNumber__v_; +text: .text%__1cISubINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cNinstanceKlassOset_alloc_size6MI_v_: instanceKlass.o; +text: .text%__1cNinstanceKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: instanceKlass.o; +text: .text%__1cHMemNodeHsize_of6kM_I_; +text: .text%__1cFVTuneQstart_class_load6F_v_; +text: .text%__1cSThreadProfilerMark2T6M_v_; +text: .text%__1cFVTuneOend_class_load6F_v_; +text: .text%__1cLClassLoaderOload_classfile6FnMsymbolHandle_pnGThread__nTinstanceKlassHandle__; +text: .text%__1cJEventMark2t6MpkcE_v_: classLoader.o; +text: .text%__1cSThreadProfilerMark2t6Mn0AGRegion__v_; +text: .text%__1cQSystemDictionaryRload_shared_class6FnTinstanceKlassHandle_nGHandle_pnGThread__1_; +text: .text%__1cKklassKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cPClassFileParserbKparse_classfile_sourcefile_attribute6MnSconstantPoolHandle_nTinstanceKlassHandle_pnGThread__v_; +text: .text%__1cQmodI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cLRShiftINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cKCMoveINodeGOpcode6kM_i_; +text: .text%__1cLLShiftLNodeGOpcode6kM_i_; +text: .text%__1cYcompareAndSwapL_boolNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSinstanceKlassKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cNinstanceKlassScopy_static_fields6MpnSPSPromotionManager__v_; +text: .text%__1cMtlsLoadPNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cFStateQ_sub_Op_URShiftI6MpknENode__v_; +text: .text%__1cKcmpOpUOperGnegate6M_v_: ad_sparc_clone.o; +text: .text%__1cObranchConUNodeGnegate6M_v_: ad_sparc_misc.o; +text: .text%__1cQaddP_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOGenerateOopMapJinterp_bb6MpnKBasicBlock__v_; +text: .text%__1cOGenerateOopMapQnext_bb_start_pc6MpnKBasicBlock__i_; +text: .text%__1cLklassVtableYadd_new_mirandas_to_list6FpnNGrowableArray4CpnNmethodOopDesc___pnPobjArrayOopDesc_6pnMklassOopDesc__v_; +text: .text%__1cIRewriterHrewrite6FnTinstanceKlassHandle_pnGThread__v_; +text: .text%__1cNinstanceKlassNrewrite_class6MpnGThread__v_; +text: .text%__1cYconstantPoolCacheOopDescKinitialize6MrnIintArray__v_; +text: .text%JVM_GetMethodIxSignatureUTF; +text: .text%JVM_GetMethodIxMaxStack; +text: .text%JVM_GetMethodIxArgsSize; +text: .text%JVM_GetMethodIxByteCodeLength; +text: .text%JVM_GetMethodIxExceptionIndexes; +text: .text%JVM_GetMethodIxByteCode; +text: .text%JVM_GetMethodIxExceptionsCount; +text: .text%__1cLstoreP0NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cHCmpNodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cMPhaseChaitinSbuild_ifg_physical6MpnMResourceArea__I_; +text: .text%__1cWCountInterfacesClosureEdoit6MpnMklassOopDesc_i_v_: klassVtable.o; +text: .text%__1cQmulD_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cKoopFactoryWnew_permanent_intArray6FipnGThread__pnQtypeArrayOopDesc__; +text: .text%__1cPClassFileParserVparse_exception_table6MIInSconstantPoolHandle_pnGThread__nPtypeArrayHandle__; +text: .text%__1cNPhaseCoalescePcoalesce_driver6M_v_; +text: .text%__1cLBuildCutout2T6M_v_; +text: .text%__1cNloadConL0NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cJloadFNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cNloadConP0NodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cJimmP0OperEtype6kM_pknEType__: ad_sparc_clone.o; +text: .text%__1cLstoreI0NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPCheckCastPPNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cSObjectSynchronizerJnotifyall6FnGHandle_pnGThread__v_; +text: .text%__1cHNTarjanICOMPRESS6M_v_; +text: .text%__1cNRelocIteratorTlocs_and_index_size6Fii_i_; +text: .text%__1cQsubL_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOcompI_iRegNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cLklassItableTcompute_itable_size6FnOobjArrayHandle__i_; +text: .text%__1cQandI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cIXorINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cRmethodDataOopDescLbci_to_data6Mi_pnLProfileData__; +text: .text%__1cFframeZinterpreter_frame_set_bcx6Mi_v_; +text: .text%__1cMnegF_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cLstoreI0NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cTOopMapForCacheEntryZfill_stackmap_for_opcodes6MpnOBytecodeStream_pnNCellTypeState_4i_v_; +text: .text%__1cSaddL_reg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQshrL_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cKstoreLNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cNSharedRuntimebKexception_handler_for_return_address6FpC_1_; +text: .text%__1cILoopNodeHsize_of6kM_I_: classes.o; +text: .text%__1cHMatcherLfind_shared6MpnENode__v_; +text: .text%__1cJStartNodeHsize_of6kM_I_; +text: .text%__1cHMatcherFxform6MpnENode_i_2_; +text: .text%__1cEDict2t6MpFpkv2_ipF2_ipnFArena_i_v_; +text: .text%__1cRInterpretedRFrameKtop_vframe6kM_pnKjavaVFrame__: rframe.o; +text: .text%__1cQmodI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cRinterpretedVFrameDbci6kM_i_; +text: .text%__1cIAndINodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cIAndINodeGmul_id6kM_pknEType__: classes.o; +text: .text%__1cNinstanceKlassbBcall_class_initializer_impl6FnTinstanceKlassHandle_pnGThread__v_; +text: .text%__1cNloadRangeNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cRcompL_reg_conNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cMLinkResolverbHlookup_instance_method_in_klasses6FrnMmethodHandle_nLKlassHandle_nMsymbolHandle_4pnGThread__v_; +text: .text%__1cMnegF_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cNSharedRuntimebWnative_method_throw_unsatisfied_link_error_entry6F_pC_; +text: .text%__1cTStackWalkCompPolicyYmethod_back_branch_event6MnMmethodHandle_iipnGThread__v_; +text: .text%__1cRCompilationPolicybJreset_counter_for_back_branch_event6MnMmethodHandle__v_; +text: .text%__1cOMethodLivenessQcompute_liveness6M_v_; +text: .text%__1cOMethodLiveness2t6MpnFArena_pnIciMethod__v_; +text: .text%__1cOMethodLivenessNinit_gen_kill6M_v_; +text: .text%__1cOMethodLivenessSpropagate_liveness6M_v_; +text: .text%__1cOMethodLivenessRinit_basic_blocks6M_v_; +text: .text%__1cIGraphKitHopt_iff6MpnENode_2_2_; +text: .text%__1cLRShiftINodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cJTimeStampGupdate6M_v_; +text: .text%__1cRmethodDataOopDescKmileage_of6FpnNmethodOopDesc__i_; +text: .text%__1cWconstantPoolCacheKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cMloadConDNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cFParseQarray_addressing6MnJBasicType_ippknEType__pnENode__; +text: .text%__1cNloadConP0NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQaddL_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPCountedLoopNodeHsize_of6kM_I_: classes.o; +text: .text%__1cIProjNodeJideal_reg6kM_I_; +text: .text%__1cQaddI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQcmovI_reg_ltNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cRsubI_zero_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cJcmpOpOperFequal6kM_i_: ad_sparc_clone.o; +text: .text%__1cHCompilebAvarargs_C_out_slots_killed6kM_I_; +text: .text%__1cXJNI_ArgumentPusherVaArgHiterate6MX_v_: jni.o; +text: .text%__1cbBjava_lang_ref_SoftReferenceFclock6F_x_; +text: .text%__1cOPhaseIdealLoopQset_subtree_ctrl6MpnENode__v_; +text: .text%__1cWstatic_call_RelocationEtype6M_nJrelocInfoJrelocType__: relocInfo.o; +text: .text%__1cNflagsRegLOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cYciExceptionHandlerStreamPcount_remaining6M_i_; +text: .text%__1cFParseXcatch_inline_exceptions6MpnNSafePointNode__v_; +text: .text%__1cRconstantPoolKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cNobjArrayKlassKcopy_array6MpnMarrayOopDesc_i2iipnGThread__v_; +text: .text%__1cKcmpOpUOperNgreater_equal6kM_i_: ad_sparc_clone.o; +text: .text%JVM_GetFieldIxModifiers; +text: .text%__1cRScavengeRootsTaskFdo_it6MpnNGCTaskManager_I_v_; +text: .text%__1cRScavengeRootsTaskEname6M_pc_: psTasks.o; +text: .text%JVM_IsConstructorIx; +text: .text%__1cPJavaCallWrapperHoops_do6MpnKOopClosure__v_; +text: .text%__1cFframeNoops_entry_do6MpnKOopClosure_pknLRegisterMap__v_; +text: .text%__1cSaddP_reg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cFKlassTarray_klass_or_null6M_pnMklassOopDesc__; +text: .text%__1cKNativeCallXset_destination_mt_safe6MpC_v_; +text: .text%__1cUBytecode_tableswitchOdest_offset_at6kMi_i_; +text: .text%__1cPciObjArrayKlassNelement_klass6M_pnHciKlass__; +text: .text%__1cKg1RegIOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cSvframeStreamCommonZsecurity_get_caller_frame6Mi_v_; +text: .text%__1cUjni_invoke_nonstatic6FpnHJNIEnv__pnJJavaValue_pnI_jobject_nLJNICallType_pnK_jmethodID_pnSJNI_ArgumentPusher_pnGThread__v_: jni.o; +text: .text%__1cIAndINodeKmul_opcode6kM_i_: classes.o; +text: .text%__1cIAndINodeKadd_opcode6kM_i_: classes.o; +text: .text%__1cTMachCallRuntimeNodePret_addr_offset6M_i_; +text: .text%__1cLConvL2INodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cKo0RegPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cIregDOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cNmethodOopDescTverified_code_entry6M_pC_; +text: .text%__1cNSharedRuntimeXfind_callee_info_helper6FpnKJavaThread_rnMvframeStream_rnJBytecodesECode_rnICallInfo_pnGThread__nGHandle__; +text: .text%__1cPBytecode_invokeFindex6kM_i_; +text: .text%__1cLRethrowNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cSPSKeepAliveClosureGdo_oop6MppnHoopDesc__v_: psScavenge.o; +text: .text%__1cFParseFBlockRsuccessor_for_bci6Mi_p1_; +text: .text%__1cVPreserveExceptionMark2T6M_v_; +text: .text%__1cVPreserveExceptionMark2t6MrpnGThread__v_; +text: .text%__1cHRetNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIRootNodeFValue6kMpnOPhaseTransform__pknEType__: classes.o; +text: .text%__1cMoutputStreamFprint6MpkcE_v_; +text: .text%__1cOGenerateOopMapKcopy_state6MpnNCellTypeState_2_v_; +text: .text%__1cHCompileQsync_stack_slots6kM_i_; +text: .text%__1cHMulNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cJLoadFNodeGOpcode6kM_i_; +text: .text%__1cNSignatureInfoHdo_long6M_v_: bytecode.o; +text: .text%__1cHPhiNodeDcmp6kMrknENode__I_; +text: .text%__1cHOrINodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cSTailCalljmpIndNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKMemoryPoolHoops_do6MpnKOopClosure__v_; +text: .text%__1cKstoreINodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRloadConP_pollNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cPClassFileStreamGget_u86MpnGThread__X_; +text: .text%__1cLMachNopNodeMideal_Opcode6kM_i_: ad_sparc.o; +text: .text%__1cLMachNopNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOPhaseIdealLoopNreorg_offsets6MpnNIdealLoopTree__v_; +text: .text%__1cRshrL_reg_imm6NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cNmethodOopDescVset_signature_handler6MpC_v_; +text: .text%__1cbBjava_lang_ref_SoftReferenceJtimestamp6FpnHoopDesc__x_; +text: .text%__1cPcompP_iRegPNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSxorI_reg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOPhaseIdealLoopRsplit_thru_region6MpnENode_2_2_; +text: .text%__1cIAndLNodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cbAPSEvacuateFollowersClosureHdo_void6M_v_: psScavenge.o; +text: .text%jni_ExceptionCheck: jni.o; +text: .text%__1cIAndLNodeImul_ring6kMpknEType_3_3_; +text: .text%__1cJCodeCacheMfind_nmethod6Fpv_pnHnmethod__; +text: .text%__1cOPhaseIdealLoopMdominated_by6MpnENode_2_v_; +text: .text%__1cQshlI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cFParseNthrow_to_exit6MpnNSafePointNode__v_; +text: .text%__1cQinstanceRefKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cVConstantOopWriteValueIwrite_on6MpnUDebugInfoWriteStream__v_; +text: .text%__1cJVectorSetGslamin6Mrk0_v_; +text: .text%JVM_Clone; +text: .text%__1cRAbstractAssemblerFflush6M_v_; +text: .text%__1cITypeLongFxdual6kM_pknEType__; +text: .text%__1cIJumpDataPpost_initialize6MpnOBytecodeStream_pnRmethodDataOopDesc__v_; +text: .text%__1cKCompiledIC2t6MpnKNativeCall__v_; +text: .text%__1cOstackSlotLOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cURethrowExceptionNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cRshrL_reg_imm6NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLOpaque2NodeEhash6kM_I_; +text: .text%__1cJloadFNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cUcompU_iReg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKstoreINodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cUEdenMutableSpacePoolQget_memory_usage6M_nLMemoryUsage__; +text: .text%__1cYSurvivorMutableSpacePoolQget_memory_usage6M_nLMemoryUsage__; +text: .text%__1cLOptoRuntimeJstub_name6FpC_pkc_; +text: .text%__1cHOrINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cICmpLNodeDsub6kMpknEType_3_3_; +text: .text%__1cHPhiNodeKmake_blank6FpnENode_2_p0_; +text: .text%__1cXJNI_ArgumentPusherVaArgIget_long6M_v_: jni.o; +text: .text%__1cIMulINodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cOMachEpilogNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cFStateM_sub_Op_SubI6MpknENode__v_; +text: .text%__1cFframeRretrieve_receiver6MpnLRegisterMap__pnHoopDesc__; +text: .text%__1cPBytecode_invokeNstatic_target6MpnGThread__nMmethodHandle__; +text: .text%__1cNloadKlassNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cMTailCallNodeKmatch_edge6kMI_I_; +text: .text%jni_NewObject: jni.o; +text: .text%__1cIPhaseIFGYCompute_Effective_Degree6M_v_; +text: .text%__1cHMemNodeIadr_type6kM_pknHTypePtr__; +text: .text%__1cXmembar_release_lockNodeIadr_type6kM_pknHTypePtr__; +text: .text%__1cJNode_ListEyank6MpnENode__v_; +text: .text%__1cMPhaseChaitinISimplify6M_v_; +text: .text%__1cNIdealLoopTreeIset_nest6MI_i_; +text: .text%__1cSCallLeafDirectNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cIMulLNodeImul_ring6kMpknEType_3_3_; +text: .text%__1cMStartOSRNodeGOpcode6kM_i_; +text: .text%__1cSCallLeafDirectNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cIMulLNodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cLcmpD_ccNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cJcmpOpOperEless6kM_i_: ad_sparc_clone.o; +text: .text%__1cKciTypeFlowPflow_exceptions6MpnNGrowableArray4Cpn0AFBlock___pnNGrowableArray4CpnPciInstanceKlass___pn0ALStateVector__v_; +text: .text%__1cKType_ArrayEgrow6MI_v_; +text: .text%__1cNloadConP0NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cXmembar_release_lockNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPconvF2D_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRshrL_reg_imm6NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMURShiftLNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cMLinkResolverOresolve_method6FrnMmethodHandle_rnLKlassHandle_nSconstantPoolHandle_ipnGThread__v_; +text: .text%__1cVshrL_reg_imm6_L2INodeIpipeline6kM_pknIPipeline__; +text: .text%__1cSMemBarVolatileNodeGOpcode6kM_i_; +text: .text%__1cLstoreB0NodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cRshrI_reg_imm5NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQjava_lang_StringOas_utf8_string6FpnHoopDesc__pc_; +text: .text%__1cRcmpFastUnlockNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cNSafePointNodeLpop_monitor6M_v_; +text: .text%__1cMPhaseChaitinVfind_base_for_derived6MppnENode_2rI_2_; +text: .text%__1cLOptoRuntimebAcomplete_monitor_exit_Type6F_pknITypeFunc__; +text: .text%__1cOstackSlotIOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cIGraphKitNshared_unlock6MpnENode_2_v_; +text: .text%__1cFStateT_sub_Op_CheckCastPP6MpknENode__v_; +text: .text%__1cQsubI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cFKlassDLCA6Mp0_1_; +text: .text%__1cKTypeRawPtrEmake6FnHTypePtrDPTR__pk0_; +text: .text%__1cHciKlassVleast_common_ancestor6Mp0_1_; +text: .text%__1cOPhaseIdealLoopPbuild_loop_tree6M_v_; +text: .text%__1cRcompL_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRshlL_reg_imm6NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cRloadConP_pollNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQshlL_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cMindirectOperEbase6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cMindirectOperFindex6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cMindirectOperEdisp6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cNSafePointNodeMpush_monitor6MpknMFastLockNode__v_; +text: .text%__1cSCallLeafDirectNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSCallLeafDirectNodeKmethod_set6Mi_v_; +text: .text%__1cIDivINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cJLoadBNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cJloadBNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cPCountedLoopNodeJinit_trip6kM_pnENode__: cfgnode.o; +text: .text%__1cRcompL_reg_conNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cPcheckCastPPNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOGenerateOopMapGdo_ldc6Mii_v_; +text: .text%__1cJCMoveNodeLis_cmove_id6FpnOPhaseTransform_pnENode_44pnIBoolNode__4_; +text: .text%__1cKTypeAryPtrQcast_to_ptr_type6kMnHTypePtrDPTR__pknEType__; +text: .text%__1cOPhaseIdealLoopKDominators6M_v_; +text: .text%__1cOPhaseIdealLoopPbuild_loop_late6MrnJVectorSet_rnJNode_List_rnKNode_Stack_pk0_v_; +text: .text%__1cOPhaseIdealLoopQbuild_loop_early6MrnJVectorSet_rnJNode_List_rnKNode_Stack_pk0_v_; +text: .text%jni_NewGlobalRef: jni.o; +text: .text%__1cTciConstantPoolCache2t6MpnFArena_i_v_; +text: .text%__1cIAndINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cYcompareAndSwapL_boolNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cMPhaseChaitinFSplit6MI_I_; +text: .text%__1cMPhaseChaitinHcompact6M_v_; +text: .text%__1cZPhaseConservativeCoalesce2t6MrnMPhaseChaitin__v_; +text: .text%__1cMPhaseChaitinZcompress_uf_map_for_nodes6M_v_; +text: .text%__1cZPhaseConservativeCoalesceGverify6M_v_; +text: .text%__1cRcmpFastUnlockNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQshlI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cXmembar_release_lockNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cKPSYoungGenNused_in_bytes6kM_I_; +text: .text%__1cOMachEpilogNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKCompiledICSset_to_monomorphic6MrknOCompiledICInfo__v_; +text: .text%__1cJloadFNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIRootNodeIIdentity6MpnOPhaseTransform__pnENode__: classes.o; +text: .text%__1cJLoadLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cTjava_lang_ThrowableTfill_in_stack_trace6FnGHandle__v_; +text: .text%__1cTjava_lang_ThrowableTfill_in_stack_trace6FnGHandle_pnGThread__v_; +text: .text%__1cFframeZinterpreter_frame_set_bcp6MpC_v_; +text: .text%JVM_FillInStackTrace; +text: .text%__1cKJavaThreadGactive6F_p0_; +text: .text%__1cKstoreFNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cQjava_lang_StringOchar_converter6FnGHandle_HHpnGThread__1_; +text: .text%__1cMVirtualSpaceNreserved_size6kM_I_; +text: .text%__1cICodeHeapMmax_capacity6kM_I_; +text: .text%__1cRsubI_zero_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cHTypePtrFxmeet6kMpknEType__3_; +text: .text%__1cNflagsRegFOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cIMinINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cFParseWensure_phis_everywhere6M_v_; +text: .text%__1cLRethrowNodeEhash6kM_I_: classes.o; +text: .text%__1cIDivLNodeGOpcode6kM_i_; +text: .text%__1cPlocal_vsnprintf6FpcIpkcpv_i_; +text: .text%__1cNDispatchTableJset_entry6MirnKEntryPoint__v_; +text: .text%__1cNmethodOopDescVclear_native_function6M_v_; +text: .text%__1cOloadConL13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cQsubL_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%jio_snprintf; +text: .text%__1cMloadConINodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSSetupItableClosureEdoit6MpnMklassOopDesc_i_v_: klassVtable.o; +text: .text%__1cSmulI_reg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%jni_NewLocalRef: jni.o; +text: .text%__1cIMulDNodeGOpcode6kM_i_; +text: .text%__1cLStrCompNodeGOpcode6kM_i_; +text: .text%__1cQcmovI_reg_gtNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cPClassFileParserbNparse_classfile_inner_classes_attribute6MnSconstantPoolHandle_nTinstanceKlassHandle_pnGThread__H_; +text: .text%__1cKStoreFNodeGOpcode6kM_i_; +text: .text%__1cLConvD2INodeGOpcode6kM_i_; +text: .text%__1cIAddLNodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cMURShiftLNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cKReturnNodeJideal_reg6kM_I_: classes.o; +text: .text%jni_DeleteGlobalRef: jni.o; +text: .text%__1cVPatchingRelocIteratorIpostpass6M_v_; +text: .text%__1cVPatchingRelocIteratorHprepass6M_v_; +text: .text%__1cRAbstractAssemblerOcode_fill_byte6F_i_; +text: .text%__1cIAndLNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cIAndLNodeGmul_id6kM_pknEType__: classes.o; +text: .text%__1cJOopMapSet2t6M_v_; +text: .text%__1cNSCMemProjNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%JVM_GetCPMethodModifiers; +text: .text%jni_GetObjectArrayElement: jni.o; +text: .text%__1cFParseKarray_load6MnJBasicType__v_; +text: .text%jni_SetLongField: jni.o; +text: .text%__1cHGCCauseJto_string6Fn0AFCause__pkc_; +text: .text%__1cJOopMapSetHcopy_to6MpC_v_; +text: .text%__1cQjava_lang_ThreadRset_thread_status6FpnHoopDesc_n0AMThreadStatus__v_; +text: .text%__1cJOopMapSetJheap_size6kM_i_; +text: .text%__1cNSafePointNodeKgrow_stack6MpnIJVMState_I_v_; +text: .text%__1cIJVMState2t6Mi_v_; +text: .text%__1cIAndLNodeKadd_opcode6kM_i_: classes.o; +text: .text%__1cIAndLNodeKmul_opcode6kM_i_: classes.o; +text: .text%__1cJLoadSNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cMMachProjNodeHsize_of6kM_I_: classes.o; +text: .text%__1cOPhaseIdealLoopUsplit_if_with_blocks6MrnJVectorSet_rnKNode_Stack__v_; +text: .text%__1cNinstanceKlassPadd_implementor6MpnMklassOopDesc__v_; +text: .text%__1cLOopRecorderIoop_size6M_i_; +text: .text%__1cYDebugInformationRecorderJdata_size6M_i_; +text: .text%__1cYDebugInformationRecorderIpcs_size6M_i_; +text: .text%__1cOPhaseIdealLoopOset_early_ctrl6MpnENode__v_; +text: .text%__1cHnmethodKtotal_size6kM_i_; +text: .text%__1cbFunnecessary_membar_volatileNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMloadConLNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cFParseNadd_safepoint6M_v_; +text: .text%__1cOPhaseTransform2t6Mp0nFPhaseLPhaseNumber__v_; +text: .text%__1cLPhaseValues2t6Mp0_v_; +text: .text%__1cQcmovI_reg_ltNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cXPhaseAggressiveCoalesceGverify6M_v_: coalesce.o; +text: .text%__1cHCompilebBregister_library_intrinsics6M_v_; +text: .text%__1cXPhaseAggressiveCoalesceNinsert_copies6MrnHMatcher__v_; +text: .text%__1cNPhaseRegAlloc2t6MIrnIPhaseCFG_rnHMatcher_pF_v_v_; +text: .text%__1cIPhaseCFGJbuild_cfg6M_I_; +text: .text%__1cHCompileEInit6Mi_v_; +text: .text%__1cVExceptionHandlerTable2t6Mi_v_; +text: .text%__1cMPhaseChaitin2t6MIrnIPhaseCFG_rnHMatcher__v_; +text: .text%__1cMPhaseChaitinRRegister_Allocate6M_v_; +text: .text%__1cHCompileTset_cached_top_node6MpnENode__v_; +text: .text%__1cHMatcherZnumber_of_saved_registers6F_i_; +text: .text%__1cNPhaseRegAllocTpd_preallocate_hook6M_v_; +text: .text%__1cLBlock_Array2t6MpnFArena__v_: block.o; +text: .text%__1cMPhaseChaitinMreset_uf_map6MI_v_; +text: .text%__1cMPhaseChaitinRbuild_ifg_virtual6M_v_; +text: .text%__1cIPhaseCFGQGlobalCodeMotion6MrnHMatcher_IrnJNode_List__v_; +text: .text%__1cHMatcherTFixup_Save_On_Entry6M_v_; +text: .text%__1cHMatcherPinit_spill_mask6MpnENode__v_; +text: .text%__1cHCompileICode_Gen6M_v_; +text: .text%__1cFArena2t6MI_v_; +text: .text%__1cUDebugInfoWriteStream2t6MpnYDebugInformationRecorder_i_v_; +text: .text%__1cHMatcherVinit_first_stack_mask6M_v_; +text: .text%__1cFArenaNmove_contents6Mp0_1_; +text: .text%__1cFArenaRdestruct_contents6M_v_; +text: .text%__1cIPhaseIFG2t6MpnFArena__v_; +text: .text%__1cFDictIFreset6MpknEDict__v_; +text: .text%__1cHMatcherFmatch6M_v_; +text: .text%__1cHMatcher2t6MrnJNode_List__v_; +text: .text%__1cIPhaseCFGVschedule_pinned_nodes6MrnJVectorSet__v_; +text: .text%__1cETypeKInitialize6FpnHCompile__v_; +text: .text%__1cIPhaseCFGYEstimate_Block_Frequency6M_v_; +text: .text%__1cYDebugInformationRecorder2t6MpnLOopRecorder__v_; +text: .text%__1cOCompileWrapper2t6MpnHCompile__v_; +text: .text%__1cIPhaseCFGKDominators6M_v_; +text: .text%__1cIPhaseCFG2t6MpnFArena_pnIRootNode_rnHMatcher__v_; +text: .text%__1cJPhaseLive2t6MrknIPhaseCFG_rnILRG_List_pnFArena__v_; +text: .text%__1cHCompileYinit_scratch_buffer_blob6M_v_; +text: .text%__1cOMachPrologNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cHCompileTFillExceptionTables6MIpI1pnFLabel__v_; +text: .text%__1cMPhaseChaitinbApost_allocate_copy_removal6M_v_; +text: .text%__1cHCompileGOutput6M_v_; +text: .text%__1cWImplicitExceptionTableIset_size6MI_v_; +text: .text%__1cHCompileMBuildOopMaps6M_v_; +text: .text%__1cLdo_liveness6FpnNPhaseRegAlloc_pnIPhaseCFG_pnKBlock_List_ipnFArena_pnEDict__v_: buildOopMap.o; +text: .text%__1cMPhaseChaitinMfixup_spills6M_v_; +text: .text%__1cNPhaseRegAllocPalloc_node_regs6Mi_v_; +text: .text%__1cHCompileLFill_buffer6M_v_; +text: .text%__1cVCallRuntimeDirectNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cNSignatureInfoJdo_double6M_v_: bytecode.o; +text: .text%__1cENodeHrm_prec6MI_v_; +text: .text%__1cHRetNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKstoreFNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cRPrivilegedElementKinitialize6MpnMvframeStream_pnHoopDesc_p0pnGThread__v_; +text: .text%JVM_DoPrivileged; +text: .text%__1cRsubI_zero_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cHRetNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIConDNodeGOpcode6kM_i_; +text: .text%__1cObranchConFNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cTresource_free_bytes6FpcI_v_; +text: .text%__1cNmethodOopDescbDbuild_interpreter_method_data6FnMmethodHandle_pnGThread__v_; +text: .text%__1cRcompL_reg_conNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNMemoryManagerHoops_do6MpnKOopClosure__v_; +text: .text%__1cPconvL2I_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cFciEnvKcompile_id6M_I_; +text: .text%__1cPmethodDataKlassIallocate6MnMmethodHandle_pnGThread__pnRmethodDataOopDesc__; +text: .text%__1cKoopFactoryOnew_methodData6FnMmethodHandle_pnGThread__pnRmethodDataOopDesc__; +text: .text%__1cIAndLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cKCodeBuffer2t6MpCi_v_; +text: .text%__1cVshrL_reg_imm6_L2INodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cLConvL2INodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cIciMethodRinstructions_size6M_i_; +text: .text%__1cSmulI_reg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cCosXthread_local_storage_at6Fi_pv_; +text: .text%__1cMindIndexOperNconstant_disp6kM_i_: ad_sparc.o; +text: .text%__1cMindIndexOperOindex_position6kM_i_: ad_sparc.o; +text: .text%__1cMindIndexOperFscale6kM_i_: ad_sparc.o; +text: .text%__1cOMacroAssemblerWbang_stack_with_offset6Mi_v_: assembler_sparc.o; +text: .text%__1cRAbstractAssemblerbDgenerate_stack_overflow_check6Mi_v_; +text: .text%__1cMindIndexOperNbase_position6kM_i_: ad_sparc.o; +text: .text%__1cNloadKlassNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cFStateR_sub_Op_LoadKlass6MpknENode__v_; +text: .text%__1cGTarjanICOMPRESS6M_v_; +text: .text%__1cKstoreCNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cICmpDNodeGOpcode6kM_i_; +text: .text%__1cNloadConL0NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cIMulLNodeGmul_id6kM_pknEType__: classes.o; +text: .text%__1cOPhaseIdealLoopOplace_near_use6kMpnENode__2_; +text: .text%__1cVCallRuntimeDirectNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cLstoreB0NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSInterpreterRuntimeOprofile_method6FpnKJavaThread_pC_i_; +text: .text%__1cMURShiftLNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cJloadPNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cLOopMapCacheLoop_iterate6MpnKOopClosure__v_; +text: .text%__1cLRShiftINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cIMachNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cLOpaque2NodeLbottom_type6kM_pknEType__: connode.o; +text: .text%__1cSconvI2D_helperNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cUPSGenerationCountersKupdate_all6M_v_: psGenerationCounters.o; +text: .text%__1cQComputeCallStackHdo_long6M_v_: generateOopMap.o; +text: .text%__1cKTypeOopPtrSmake_from_constant6FpnIciObject__pk0_; +text: .text%__1cQregP_to_stkPNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOGenerateOopMapHppstore6MpnNCellTypeState_i_v_; +text: .text%__1cJTimeStampSticks_since_update6kM_x_; +text: .text%__1cQmodI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cIMulINodeImul_ring6kMpknEType_3_3_; +text: .text%__1cURethrowExceptionNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIAddLNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cQcmovI_reg_ltNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLstoreB0NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSaddI_reg_imm13NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cIModINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cKklassKlassIoop_size6kMpnHoopDesc__i_; +text: .text%__1cJcmpOpOperHgreater6kM_i_: ad_sparc_clone.o; +text: .text%__1cJimmL0OperJconstantL6kM_x_: ad_sparc_clone.o; +text: .text%__1cJimmI0OperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cFStateM_sub_Op_ConL6MpknENode__v_; +text: .text%__1cOloadConL13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cNObjectMonitorHis_busy6kM_i_; +text: .text%JVM_GetClassNameUTF; +text: .text%__1cKloadUBNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIXorINodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cFStateM_sub_Op_AndI6MpknENode__v_; +text: .text%__1cVshrL_reg_imm6_L2INodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKcmpOpFOperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cLRuntimeStubHoops_do6MpnKOopClosure__v_: codeBlob.o; +text: .text%__1cTmembar_volatileNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJloadFNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cFStateL_sub_Op_OrI6MpknENode__v_; +text: .text%__1cJCmpL3NodeGOpcode6kM_i_; +text: .text%JVM_FindLoadedClass; +text: .text%__1cIMulLNodeKadd_opcode6kM_i_: classes.o; +text: .text%__1cIMulLNodeKmul_opcode6kM_i_: classes.o; +text: .text%__1cVAdaptivePaddedAverageGsample6Mf_v_; +text: .text%__1cIConFNodeGOpcode6kM_i_; +text: .text%__1cSmembar_acquireNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cQmulD_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIModLNodeGOpcode6kM_i_; +text: .text%__1cbIjava_lang_reflect_AccessibleObjectIoverride6FpnHoopDesc__C_; +text: .text%__1cQLibraryIntrinsicIgenerate6MpnIJVMState__2_; +text: .text%__1cLRShiftLNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cKTypeRawPtrFxdual6kM_pknEType__; +text: .text%__1cNloadConL0NodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cFTypeFEmake6Ff_pk0_; +text: .text%__1cIimmFOperJconstantF6kM_f_: ad_sparc_clone.o; +text: .text%__1cEUTF8Ounicode_length6Fpkc_i_; +text: .text%__1cCosRcurrent_thread_id6F_i_; +text: .text%__1cUSafepointSynchronizeFblock6FpnKJavaThread__v_; +text: .text%__1cOGenerateOopMapJppdupswap6Mipkc_v_; +text: .text%__1cJttyLockerbCbreak_tty_lock_for_safepoint6Fi_v_; +text: .text%__1cSmembar_acquireNodeIadr_type6kM_pknHTypePtr__; +text: .text%__1cPorI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIPhaseCFGOinsert_goto_at6MII_v_; +text: .text%__1cITypeLongFwiden6kMpknEType__3_; +text: .text%__1cSThreadLocalStoragePget_thread_slow6F_pnGThread__; +text: .text%__1cPCallRuntimeNodeGOpcode6kM_i_; +text: .text%__1cJcmpOpOperNgreater_equal6kM_i_: ad_sparc_clone.o; +text: .text%__1cMindIndexOperFindex6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cMindIndexOperEbase6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cMindIndexOperEdisp6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%JVM_FindClassFromClass; +text: .text%__1cRshrP_reg_imm5NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cObranchConFNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cQshrI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cbDjava_lang_reflect_ConstructorFclazz6FpnHoopDesc__2_; +text: .text%__1cbDjava_lang_reflect_ConstructorEslot6FpnHoopDesc__i_; +text: .text%__1cbDjava_lang_reflect_ConstructorPparameter_types6FpnHoopDesc__2_; +text: .text%__1cKReflectionSinvoke_constructor6FpnHoopDesc_nOobjArrayHandle_pnGThread__2_; +text: .text%JVM_NewInstanceFromConstructor; +text: .text%__1cFParseFBlockMadd_new_path6M_i_; +text: .text%__1cIimmPOperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cQsubL_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cJloadBNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cLConvF2DNodeGOpcode6kM_i_; +text: .text%__1cLConvI2DNodeGOpcode6kM_i_; +text: .text%__1cSciExceptionHandlerLcatch_klass6M_pnPciInstanceKlass__; +text: .text%__1cMloadConFNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cKcmpOpPOperNgreater_equal6kM_i_: ad_sparc_clone.o; +text: .text%__1cLRShiftLNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cKimmL13OperJconstantL6kM_x_: ad_sparc_clone.o; +text: .text%__1cSTailCalljmpIndNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cKstoreLNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cGIfNodeMdominated_by6MpnENode_pnMPhaseIterGVN__v_; +text: .text%__1cOcompiledVFrame2t6MpknFframe_pknLRegisterMap_pnKJavaThread_pnJScopeDesc__v_; +text: .text%__1cJScopeDesc2t6MpknHnmethod_i_v_; +text: .text%__1cQshlI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOGenerateOopMapJdo_astore6Mi_v_; +text: .text%__1cbFunnecessary_membar_volatileNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cULinearLeastSquareFitGupdate6Mdd_v_; +text: .text%__1cOoop_RelocationIoop_addr6M_ppnHoopDesc__; +text: .text%__1cKstoreCNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKstoreCNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cJcmpOpOperKless_equal6kM_i_: ad_sparc_clone.o; +text: .text%__1cXmembar_acquire_lockNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPfieldDescriptorUstring_initial_value6kMpnGThread__pnHoopDesc__; +text: .text%__1cMloadConLNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIMaxINodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cMloadConDNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cMindirectOperNconstant_disp6kM_i_: ad_sparc.o; +text: .text%__1cMindirectOperNbase_position6kM_i_: ad_sparc.o; +text: .text%__1cIAddLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cMindirectOperFscale6kM_i_: ad_sparc.o; +text: .text%__1cYinternal_word_RelocationEtype6M_nJrelocInfoJrelocType__: relocInfo.o; +text: .text%__1cSsubL_reg_reg_2NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%jni_NewString: jni.o; +text: .text%__1cLConvL2INodeJideal_reg6kM_I_: classes.o; +text: .text%__1cQjava_lang_StringXcreate_oop_from_unicode6FpHipnGThread__pnHoopDesc__; +text: .text%__1cKoopFactoryNnew_charArray6FpkcpnGThread__pnQtypeArrayOopDesc__; +text: .text%__1cOcompiledVFrameEcode6kM_pnHnmethod__; +text: .text%__1cIGraphKitMnext_monitor6M_i_; +text: .text%__1cLBoxLockNode2t6Mi_v_; +text: .text%__1cPconvF2D_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cLOptoRuntimebBcomplete_monitor_enter_Type6F_pknITypeFunc__; +text: .text%__1cIGraphKitLshared_lock6MpnENode__pnMFastLockNode__; +text: .text%__1cPcmpFastLockNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cNloadConP0NodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cRorI_reg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKcmpOpUOperEless6kM_i_: ad_sparc_clone.o; +text: .text%__1cQaddF_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRLowMemoryDetectorWdetect_after_gc_memory6FpnKMemoryPool__v_; +text: .text%lwp_mutex_init: os_solaris.o; +text: .text%__1cRsubI_zero_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cFframeLnmethods_do6M_v_; +text: .text%__1cQjava_lang_ThreadGthread6FpnHoopDesc__pnKJavaThread__; +text: .text%__1cQnotemp_iRegIOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cITemplateIbytecode6kM_nJBytecodesECode__; +text: .text%__1cODataRelocationGoffset6M_i_: relocInfo.o; +text: .text%__1cYinternal_word_RelocationFvalue6M_pC_: relocInfo.o; +text: .text%__1cCosPhint_no_preempt6F_v_; +text: .text%__1cOcmovII_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIMulLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cIMulINodeGmul_id6kM_pknEType__: classes.o; +text: .text%__1cPciObjectFactory2t6MpnFArena_i_v_; +text: .text%__1cRsarL_reg_imm6NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cFciEnvWget_method_from_handle6MpnI_jobject__pnIciMethod__; +text: .text%__1cSstring_compareNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cFciEnv2T6M_v_; +text: .text%__1cIGraphKitNgen_checkcast6MpnENode_2p2_2_; +text: .text%__1cMMergeMemNodeIadr_type6kM_pknHTypePtr__: memnode.o; +text: .text%__1cJcmpOpOperJnot_equal6kM_i_: ad_sparc_clone.o; +text: .text%__1cGvframeDtop6kM_p0_; +text: .text%__1cOCompiledRFrameEinit6M_v_; +text: .text%__1cXmembar_acquire_lockNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cJloadSNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cVCallRuntimeDirectNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cPcmpFastLockNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQciTypeArrayKlassEmake6FnJBasicType__p0_; +text: .text%__1cIXorINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cIGraphKitRgen_subtype_check6MpnENode_2_2_; +text: .text%__1cOMacroAssemblerLsave_thread6MkpnMRegisterImpl__v_; +text: .text%__1cOcmovII_immNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMloadConINodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cRshlL_reg_imm6NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cFParseGdo_new6M_v_; +text: .text%__1cIimmIOperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cQmodI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLConvI2LNodeJideal_reg6kM_I_: classes.o; +text: .text%jni_GetObjectClass: jni.o; +text: .text%__1cSxorI_reg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOMacroAssemblerFalign6Mi_v_; +text: .text%__1cRappend_interfaces6FnOobjArrayHandle_ripnPobjArrayOopDesc__v_; +text: .text%__1cKManagementJtimestamp6F_x_; +text: .text%__1cIPSOldGenPupdate_counters6M_v_; +text: .text%__1cQshrI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cFForteNregister_stub6FpkcpC3_v_; +text: .text%__1cFVTuneNregister_stub6FpkcpC3_v_; +text: .text%__1cNinstanceKlassbFlookup_method_in_all_interfaces6kMpnNsymbolOopDesc_2_pnNmethodOopDesc__; +text: .text%__1cTloadL_unalignedNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cJloadLNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cOMacroAssemblerVreset_last_Java_frame6M_v_; +text: .text%__1cOMacroAssemblerTset_last_Java_frame6MpnMRegisterImpl_2_v_; +text: .text%__1cSstring_compareNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOstackSlotIOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cQregF_to_stkINodeIpipeline6kM_pknIPipeline__; +text: .text%__1cINodeHash2t6MpnFArena_I_v_; +text: .text%__1cPconvI2L_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOPhaseTransform2t6MpnFArena_nFPhaseLPhaseNumber__v_; +text: .text%__1cLPhaseValues2t6MpnFArena_I_v_; +text: .text%__1cJStubQdDueueGcommit6Mi_v_; +text: .text%__1cJStubQdDueueHrequest6Mi_pnEStub__; +text: .text%__1cOcmovII_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKstoreFNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOMacroAssemblerKsave_frame6Mi_v_; +text: .text%__1cSmulI_reg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cLstoreC0NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOPhaseIdealLoopVclone_up_backedge_goo6MpnENode_22_2_; +text: .text%__1cITemplateKinitialize6MinITosState_1pFi_vi_v_; +text: .text%__1cITemplateIgenerate6MpnZInterpreterMacroAssembler__v_; +text: .text%JVM_FindClassFromClassLoader; +text: .text%JVM_FindClassFromBootLoader; +text: .text%signalHandler; +text: .text%__1cTtypeArrayKlassKlassIoop_size6kMpnHoopDesc__i_: typeArrayKlassKlass.o; +text: .text%JVM_handle_solaris_signal; +text: .text%__1cQjava_lang_ThreadRget_thread_status6FpnHoopDesc__n0AMThreadStatus__; +text: .text%__1cNSignatureInfoIdo_float6M_v_: bytecode.o; +text: .text%__1cFStateM_sub_Op_AndL6MpknENode__v_; +text: .text%__1cKConv2BNodeGOpcode6kM_i_; +text: .text%__1cZInterpreterMacroAssemblerZcheck_and_handle_popframe6MpnMRegisterImpl__v_; +text: .text%JVM_IHashCode; +text: .text%__1cSconvI2D_helperNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cJStartNodeJideal_reg6kM_I_: callnode.o; +text: .text%__1cOMacroAssemblerbBcheck_and_forward_exception6MpnMRegisterImpl__v_; +text: .text%__1cQcmovI_reg_ltNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cQandL_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cLPhaseValuesKis_IterGVN6M_pnMPhaseIterGVN__: phaseX.o; +text: .text%__1cMLinkResolverXresolve_invokeinterface6FrnICallInfo_nGHandle_nSconstantPoolHandle_ipnGThread__v_; +text: .text%__1cKC2CompilerOcompile_method6MpnFciEnv_pnIciMethod_i_v_; +text: .text%JVM_GetClassLoader; +text: .text%__1cNCompileBrokerZinvoke_compiler_on_method6FpnLCompileTask__v_; +text: .text%__1cCosRelapsed_frequency6F_x_; +text: .text%__1cFStateP_sub_Op_ConvL2I6MpknENode__v_; +text: .text%__1cOPhaseIdealLoopLdo_split_if6MpnENode__v_; +text: .text%__1cLAccessFlagsRatomic_clear_bits6Mi_v_; +text: .text%__1cKScheduling2t6MpnFArena_rnHCompile__v_; +text: .text%__1cKSchedulingMDoScheduling6M_v_; +text: .text%__1cNCompileBrokerScollect_statistics6FpnOCompilerThread_nMelapsedTimer_pnLCompileTask__v_; +text: .text%__1cFciEnvbOcheck_for_system_dictionary_modification6MpnIciMethod__v_; +text: .text%__1cSCardTableExtensionbAscavenge_contents_parallel6MpnQObjectStartArray_pnMMutableSpace_pnIHeapWord_pnSPSPromotionManager_I_v_; +text: .text%__1cRframe_gc_prologue6FpnFframe_pknLRegisterMap__v_: thread.o; +text: .text%__1cFframeMpd_gc_epilog6M_v_; +text: .text%__1cMelapsedTimerHseconds6kM_d_; +text: .text%__1cJStealTaskEname6M_pc_: psTasks.o; +text: .text%__1cRframe_gc_epilogue6FpnFframe_pknLRegisterMap__v_: thread.o; +text: .text%__1cFframeLgc_epilogue6M_v_; +text: .text%__1cFframeLgc_prologue6M_v_; +text: .text%__1cTOldToYoungRootsTaskEname6M_pc_: psTasks.o; +text: .text%__1cJStealTaskFdo_it6MpnNGCTaskManager_I_v_; +text: .text%__1cTOldToYoungRootsTaskFdo_it6MpnNGCTaskManager_I_v_; +text: .text%__1cNGCTaskManagerMnote_release6MI_v_; +text: .text%__1cMciMethodDataStrap_recompiled_at6MpnLProfileData__i_; +text: .text%__1cJloadLNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSmembar_acquireNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSmembar_acquireNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cYDebugInformationRecorderHcopy_to6MpnHnmethod__v_; +text: .text%__1cVExceptionHandlerTableHcopy_to6MpnHnmethod__v_; +text: .text%__1cJCodeCacheGcommit6FpnICodeBlob__v_; +text: .text%__1cFVTuneOcreate_nmethod6FpnHnmethod__v_; +text: .text%__1cHnmethodQcopy_scopes_data6MpCi_v_; +text: .text%__1cFciEnvVnum_inlined_bytecodes6kM_i_; +text: .text%__1cWImplicitExceptionTableHcopy_to6MpnHnmethod__v_; +text: .text%__1cLOopRecorderHcopy_to6MpnICodeBlob__v_; +text: .text%__1cIciMethodRbuild_method_data6M_v_; +text: .text%__1cHCompileIOptimize6M_v_; +text: .text%__1cHCompileLFinish_Warm6M_v_; +text: .text%__1cbAfinal_graph_reshaping_walk6FrnKNode_Stack_pnENode_rnUFinal_Reshape_Counts__v_: compile.o; +text: .text%__1cHCompileLInline_Warm6M_i_; +text: .text%__1cSPhaseRemoveUseless2t6MpnIPhaseGVN_pnQUnique_Node_List__v_; +text: .text%__1cJStartNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cKInlineTreeWbuild_inline_tree_root6F_p0_; +text: .text%__1cHCompileRbuild_start_state6MpnJStartNode_pknITypeFunc__pnIJVMState__; +text: .text%__1cIPhaseCCPHanalyze6M_v_; +text: .text%__1cIPhaseCCPMdo_transform6M_v_; +text: .text%__1cIPhaseCCPJtransform6MpnENode__2_; +text: .text%__1cIPhaseCCP2t6MpnMPhaseIterGVN__v_; +text: .text%__1cHCompileVidentify_useful_nodes6MrnQUnique_Node_List__v_; +text: .text%__1cHCompileUremove_useless_nodes6MrnQUnique_Node_List__v_; +text: .text%__1cQUnique_Node_ListUremove_useless_nodes6MrnJVectorSet__v_; +text: .text%__1cMPhaseIterGVN2t6MpnIPhaseGVN__v_; +text: .text%__1cMPhaseIterGVN2t6Mp0_v_; +text: .text%__1cQmulI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cNTemplateTableKtransition6FnITosState_1_v_; +text: .text%__1cHCompileNreturn_values6MpnIJVMState__v_; +text: .text%__1cOcmovII_immNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOMachEpilogNodeQsafepoint_offset6kM_i_; +text: .text%__1cZInterpreterMacroAssemblerPdispatch_epilog6MnITosState_i_v_; +text: .text%__1cZInterpreterMacroAssemblerPdispatch_prolog6MnITosState_i_v_; +text: .text%__1cIModINodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cFStateP_sub_Op_RShiftI6MpknENode__v_; +text: .text%__1cRsarI_reg_imm5NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%lwp_cond_init: os_solaris.o; +text: .text%__1cTmembar_volatileNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cNloadConL0NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQComputeCallStackGdo_int6M_v_: generateOopMap.o; +text: .text%__1cXmembar_acquire_lockNodeIadr_type6kM_pknHTypePtr__; +text: .text%__1cKPSYoungGenRcapacity_in_bytes6kM_I_; +text: .text%__1cNSafepointBlobbDpreserve_callee_argument_oops6MnFframe_pknLRegisterMap_pnKOopClosure__v_: codeBlob.o; +text: .text%__1cOloadConI13NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cJloadSNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIAddFNodeGOpcode6kM_i_; +text: .text%__1cJJavaCallsMcall_special6FpnJJavaValue_nLKlassHandle_nMsymbolHandle_4pnRJavaCallArguments_pnGThread__v_; +text: .text%__1cFStateO_sub_Op_Binary6MpknENode__v_; +text: .text%__1cKBinaryNodeGOpcode6kM_i_; +text: .text%__1cNSignatureInfoIdo_short6M_v_: bytecode.o; +text: .text%__1cLBoxLockNodeDcmp6kMrknENode__I_; +text: .text%__1cSCompiledStaticCallSset_to_interpreted6MnMmethodHandle_pC_v_; +text: .text%__1cSCompiledStaticCallJfind_stub6M_pC_; +text: .text%__1cRNativeMovConstRegIset_data6Mi_v_; +text: .text%__1cFParsebLincrement_and_test_invocation_counter6Mi_v_; +text: .text%__1cSsafePoint_pollNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cMTailCallNodeGOpcode6kM_i_; +text: .text%__1cSInterpreterRuntimeTprepare_native_call6FpnKJavaThread_pnNmethodOopDesc__v_; +text: .text%__1cXSignatureHandlerLibraryDadd6FnMmethodHandle__v_; +text: .text%__1cSsafePoint_pollNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNobjArrayKlassWcompute_modifier_flags6kMpnGThread__i_; +text: .text%__1cPClassFileParserUverify_constantvalue6MiinSconstantPoolHandle_pnGThread__v_; +text: .text%__1cZInterpreterMacroAssemblerNdispatch_next6MnITosState_i_v_; +text: .text%__1cIMulFNodeGOpcode6kM_i_; +text: .text%__1cISubLNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cQmulD_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cNSCMemProjNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cSThreadLocalStorageGthread6F_pnGThread__: assembler_sparc.o; +text: .text%jni_SetByteArrayRegion: jni.o; +text: .text%__1cQregI_to_stkINodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cQjava_lang_StringPcreate_from_str6FpkcpnGThread__nGHandle__; +text: .text%__1cSdivL_reg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cFStateM_sub_Op_XorI6MpknENode__v_; +text: .text%__1cHTypePtrEmake6FnETypeFTYPES_n0ADPTR_i_pk0_; +text: .text%__1cCosLelapsedTime6F_d_; +text: .text%__1cKScopeValueJread_from6FpnTDebugInfoReadStream__p0_; +text: .text%__1cKPerfMemoryMmark_updated6F_v_; +text: .text%__1cSobjArrayKlassKlassbCallocate_objArray_klass_impl6FnYobjArrayKlassKlassHandle_inLKlassHandle_pnGThread__pnMklassOopDesc__; +text: .text%__1cIPerfData2t6MnJCounterNS_pkcn0AFUnits_n0ALVariability__v_; +text: .text%__1cKPerfMemoryFalloc6FI_pc_; +text: .text%__1cLStrCompNodeKmatch_edge6kMI_I_; +text: .text%__1cQmulL_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cILocation2t6MpnTDebugInfoReadStream__v_; +text: .text%__1cKJavaThreadZsecurity_get_caller_class6Mi_pnMklassOopDesc__; +text: .text%jni_ReleaseStringUTFChars; +text: .text%jni_GetStringUTFChars: jni.o; +text: .text%__1cSobjArrayKlassKlassXallocate_objArray_klass6MinLKlassHandle_pnGThread__pnMklassOopDesc__; +text: .text%__1cFParseLarray_store6MnJBasicType__v_; +text: .text%__1cSInterpreterRuntimeNquicken_io_cc6FpnKJavaThread__v_; +text: .text%__1cSInterpreterRuntimeXthrow_pending_exception6FpnKJavaThread__v_; +text: .text%JVM_IsInterrupted; +text: .text%__1cLLShiftLNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cNSignatureInfoHdo_char6M_v_: bytecode.o; +text: .text%JVM_FindLibraryEntry; +text: .text%__1cWConstantPoolCacheEntrySset_interface_call6MnMmethodHandle_i_v_; +text: .text%__1cLklassItableUcompute_itable_index6FpnNmethodOopDesc__i_; +text: .text%__1cRshlL_reg_imm6NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQshlL_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cPconvF2D_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cLRShiftLNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cSstring_compareNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOMacroAssemblerEstop6Mpkc_v_; +text: .text%__1cObranchConFNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKloadUBNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQaddP_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cLcmpD_ccNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cTloadL_unalignedNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cLLShiftLNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cbIjava_lang_reflect_AccessibleObjectMset_override6FpnHoopDesc_C_v_; +text: .text%__1cXJNI_ArgumentPusherVaArgHget_int6M_v_: jni.o; +text: .text%__1cRbranchLoopEndNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQaddF_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKcmpOpUOperHgreater6kM_i_: ad_sparc_clone.o; +text: .text%__1cUParallelScavengeHeapEused6kM_I_; +text: .text%__1cIDivINodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cQmulF_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cQxorI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cWCallLeafNoFPDirectNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLcmpD_ccNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cWCallLeafNoFPDirectNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cJloadINodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cbBopt_virtual_call_RelocationLstatic_stub6M_pC_; +text: .text%__1cNTemplateTableDdef6FnJBytecodesECode_inITosState_3pFi_vi_v_; +text: .text%__1cIMinINodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cKarrayKlassKjava_super6kM_pnMklassOopDesc__; +text: .text%__1cOClearArrayNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cRbranchLoopEndNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cRbranchLoopEndNodeJlabel_set6MrnFLabel_I_v_; +text: .text%__1cLMachUEPNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cCosTnative_java_library6F_pv_; +text: .text%__1cJJavaCallsMcall_special6FpnJJavaValue_nGHandle_nLKlassHandle_nMsymbolHandle_533pnGThread__v_; +text: .text%__1cSInterpreterRuntimeOmultianewarray6FpnKJavaThread_pi_v_; +text: .text%__1cSxorI_reg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cMPhaseChaitinGSelect6M_I_; +text: .text%__1cFParseSjump_switch_ranges6MpnENode_pnLSwitchRange_4i_v_; +text: .text%__1cSbranchCon_longNodeJlabel_set6MrnFLabel_I_v_; +text: .text%__1cSbranchCon_longNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSbranchCon_longNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cCosYprint_jni_name_suffix_on6FpnMoutputStream_i_v_; +text: .text%__1cCosYprint_jni_name_prefix_on6FpnMoutputStream_i_v_; +text: .text%__1cLstoreP0NodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cFParseTprofile_switch_case6Mi_v_; +text: .text%__1cSandI_reg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIimmLOperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cFParseOmerge_new_path6Mi_v_; +text: .text%__1cQregP_to_stkPNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cQjava_lang_StringGoffset6FpnHoopDesc__i_; +text: .text%__1cQjava_lang_StringFvalue6FpnHoopDesc__pnQtypeArrayOopDesc__; +text: .text%__1cQjava_lang_StringScreate_from_symbol6FnMsymbolHandle_pnGThread__nGHandle__; +text: .text%__1cSmembar_releaseNodeLout_RegMask6kM_rknHRegMask__; +text: .text%jni_NewByteArray: jni.o; +text: .text%__1cQdivL_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cJJavaCallsMcall_special6FpnJJavaValue_nGHandle_nLKlassHandle_nMsymbolHandle_53pnGThread__v_; +text: .text%__1cQSystemDictionarybAvalidate_protection_domain6FnTinstanceKlassHandle_nGHandle_2pnGThread__v_; +text: .text%__1cKDictionaryVadd_protection_domain6MiInTinstanceKlassHandle_nGHandle_2pnGThread__v_; +text: .text%__1cFParseLdo_newarray6MnJBasicType__v_; +text: .text%__1cPmethodDataKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cNmethodOopDescKklass_name6kM_pnNsymbolOopDesc__; +text: .text%__1cSconvI2D_helperNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cLstoreP0NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cMciArrayKlass2t6MnLKlassHandle__v_; +text: .text%__1cSmembar_releaseNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIPerfLong2t6MnJCounterNS_pkcnIPerfDataFUnits_n0CLVariability__v_; +text: .text%__1cKarrayKlassXbase_create_array_klass6FrknKKlass_vtbl_inLKlassHandle_pnGThread__nQarrayKlassHandle__; +text: .text%__1cKarrayKlassbBcomplete_create_array_klass6FnQarrayKlassHandle_nLKlassHandle_pnGThread__v_; +text: .text%__1cSTailCalljmpIndNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQcmovI_reg_gtNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%JVM_GetMethodIxExceptionTableEntry; +text: .text%__1cIDivINodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cLstoreP0NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQstkI_to_regFNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cLRethrowNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cKloadUBNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cHCompileSrethrow_exceptions6MpnIJVMState__v_; +text: .text%__1cURethrowExceptionNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLRethrowNode2t6MpnENode_22222_v_; +text: .text%__1cTLoadL_unalignedNodeGOpcode6kM_i_; +text: .text%__1cSmulI_reg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cZInterpreterMacroAssemblerZget_2_byte_integer_at_bcp6MipnMRegisterImpl_2n0ALsignedOrNot_n0AKsetCCOrNot__v_; +text: .text%__1cQcmovI_reg_gtNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cURethrowExceptionNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPfieldDescriptorSlong_initial_value6kM_x_; +text: .text%__1cISubLNodeDsub6kMpknEType_3_3_; +text: .text%__1cPciObjArrayKlass2t6MnLKlassHandle__v_; +text: .text%__1cJLoadINodeMstore_Opcode6kM_i_: classes.o; +text: .text%__1cQandI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNobjArrayKlassYcompute_secondary_supers6MipnGThread__pnPobjArrayOopDesc__; +text: .text%__1cQmulI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cFParsePmerge_exception6Mi_v_; +text: .text%__1cLStrCompNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cNobjArrayKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: objArrayKlass.o; +text: .text%__1cNloadConP0NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%jni_ReleaseStringCritical: jni.o; +text: .text%__1cJCMoveNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%jni_GetStringCritical: jni.o; +text: .text%__1cHciKlassSsuper_check_offset6M_I_; +text: .text%__1cPciObjArrayKlassGloader6M_pnHoopDesc__: ciObjArrayKlass.o; +text: .text%__1cWCallLeafNoFPDirectNodeKmethod_set6Mi_v_; +text: .text%__1cWCallLeafNoFPDirectNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIDivLNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cPICStubInterfaceRcode_size_to_size6kMi_i_: icBuffer.o; +text: .text%__1cPICStubInterfaceKinitialize6MpnEStub_i_v_: icBuffer.o; +text: .text%__1cMloadConFNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMadjust_check6FpnENode_11iipnMPhaseIterGVN__v_: ifnode.o; +text: .text%__1cJScopeDescGsender6kM_p0_; +text: .text%__1cSxorI_reg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOcompiledVFrameGsender6kM_pnGvframe__; +text: .text%__1cZInterpreterMacroAssemblerDpop6MnITosState__v_; +text: .text%__1cGThreadHoops_do6MpnKOopClosure__v_; +text: .text%__1cQPlaceholderTableHoops_do6MpnKOopClosure__v_; +text: .text%__1cXJvmtiCurrentBreakpointsHoops_do6FpnKOopClosure__v_; +text: .text%__1cNMemoryServiceHoops_do6FpnKOopClosure__v_; +text: .text%__1cNThreadServiceHoops_do6FpnKOopClosure__v_; +text: .text%__1cKJNIHandlesHoops_do6FpnKOopClosure__v_; +text: .text%__1cQSystemDictionaryRpreloaded_oops_do6FpnKOopClosure__v_; +text: .text%__1cLJvmtiExportHoops_do6FpnKOopClosure__v_; +text: .text%__1cIVMThreadHoops_do6MpnKOopClosure__v_; +text: .text%__1cKJNIHandlesMweak_oops_do6FpnRBoolObjectClosure_pnKOopClosure__v_; +text: .text%__1cSObjectSynchronizerHoops_do6FpnKOopClosure__v_; +text: .text%__1cMFlatProfilerHoops_do6FpnKOopClosure__v_; +text: .text%__1cOPhaseIdealLoopOadd_constraint6MiipnENode_22p23_v_; +text: .text%__1cKManagementHoops_do6FpnKOopClosure__v_; +text: .text%__1cKstoreBNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cSaddL_reg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQSystemDictionaryRnumber_of_classes6F_i_; +text: .text%__1cQComputeCallStackIdo_short6M_v_: generateOopMap.o; +text: .text%__1cLstoreI0NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cFframeIpatch_pc6MpnGThread_pC_v_; +text: .text%__1cRtestI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cNmethodOopDescbGresolved_checked_exceptions_impl6Fp0pnGThread__nOobjArrayHandle__; +text: .text%__1cFParseMdo_checkcast6M_v_; +text: .text%__1cOCompiledRFrameKtop_method6kM_nMmethodHandle__: rframe.o; +text: .text%__1cKReflectionTget_parameter_types6FnMmethodHandle_ippnHoopDesc_pnGThread__nOobjArrayHandle__; +text: .text%__1cRtestI_reg_immNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOcmovIL_immNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cJimmU6OperIconstant6kM_i_: ad_sparc_clone.o; +text: .text%__1cHRegMask2t6M_v_: matcher.o; +text: .text%__1cOGenerateOopMapIcopy_cts6MpnNCellTypeState_2_i_; +text: .text%__1cNObjectMonitorGEnterI6MpnGThread__v_; +text: .text%__1cSmulL_reg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cPstoreI_FregNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cLcmpD_ccNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cXMachCallDynamicJavaNodePret_addr_offset6M_i_; +text: .text%__1cNflagsRegFOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cXvirtual_call_RelocationEtype6M_nJrelocInfoJrelocType__: relocInfo.o; +text: .text%__1cPPerfDataManagerMcounter_name6Fpkc2_pc_; +text: .text%__1cIModLNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cMloadConFNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cbBjava_lang_ref_SoftReferenceJset_clock6Fx_v_; +text: .text%__1cbAPSGCAdaptivePolicyCountersbBupdate_counters_from_policy6M_v_; +text: .text%__1cXTraceMemoryManagerStats2T6M_v_; +text: .text%__1cQSystemDictionaryHoops_do6FpnKOopClosure__v_; +text: .text%__1cQLRUMaxHeapPolicy2t6M_v_; +text: .text%__1cUParallelScavengeHeapQresize_all_tlabs6M_v_; +text: .text%__1cUParallelScavengeHeapPupdate_counters6M_v_; +text: .text%__1cUParallelScavengeHeapbFaccumulate_statistics_all_tlabs6M_v_; +text: .text%__1cVLoaderConstraintTableHoops_do6MpnKOopClosure__v_; +text: .text%__1cTDerivedPointerTablePupdate_pointers6F_v_; +text: .text%__1cNCollectedHeapbFaccumulate_statistics_all_tlabs6M_v_; +text: .text%__1cNCollectedHeapQresize_all_tlabs6M_v_; +text: .text%__1cMTypeKlassPtrFxmeet6kMpknEType__3_; +text: .text%__1cKPSYoungGenPupdate_counters6M_v_; +text: .text%__1cWThreadLocalAllocBufferbFaccumulate_statistics_before_gc6F_v_; +text: .text%__1cWThreadLocalAllocBufferQresize_all_tlabs6F_v_; +text: .text%__1cPGCMemoryManagerIgc_begin6M_v_; +text: .text%__1cPGCMemoryManagerGgc_end6M_v_; +text: .text%__1cRLowMemoryDetectorRdetect_low_memory6F_v_; +text: .text%__1cNMemoryServiceStrack_memory_usage6F_v_; +text: .text%__1cbAPSGCAdaptivePolicyCountersPupdate_counters6M_v_; +text: .text%__1cTDerivedPointerTableFclear6F_v_; +text: .text%__1cKDictionaryHoops_do6MpnKOopClosure__v_; +text: .text%__1cORuntimeServiceWrecord_safepoint_begin6F_v_; +text: .text%__1cSObjectSynchronizerVdeflate_idle_monitors6F_v_; +text: .text%__1cMCounterDecayFdecay6F_v_; +text: .text%__1cCosbCmake_polling_page_unreadable6F_v_; +text: .text%__1cRInlineCacheBufferUupdate_inline_caches6F_v_; +text: .text%__1cLConvI2FNodeGOpcode6kM_i_; +text: .text%__1cORuntimeServicebDrecord_safepoint_synchronized6F_v_; +text: .text%__1cQaddF_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cUSafepointSynchronizeFbegin6F_v_; +text: .text%__1cKarrayKlassTallocate_arrayArray6MiipnGThread__pnPobjArrayOopDesc__; +text: .text%__1cONMethodSweeperFsweep6F_v_; +text: .text%__1cCosbAmake_polling_page_readable6F_v_; +text: .text%__1cUSafepointSynchronizeDend6F_v_; +text: .text%__1cOcmovII_immNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cORuntimeServiceUrecord_safepoint_end6F_v_; +text: .text%__1cKimmU13OperIconstant6kM_i_: ad_sparc_clone.o; +text: .text%__1cQshlL_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cUcompU_iReg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%JVM_GetCallerClass; +text: .text%__1cNSignatureInfoHdo_byte6M_v_: bytecode.o; +text: .text%__1cOcmovPP_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKstoreBNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSobjArrayKlassKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cLstoreC0NodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cTloadL_unalignedNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cICmpFNodeGOpcode6kM_i_; +text: .text%__1cOstackSlotPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cQregF_to_stkINodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cJLoadDNodeGOpcode6kM_i_; +text: .text%__1cQmulD_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%jni_IsAssignableFrom: jni.o; +text: .text%jni_GetFieldID: jni.o; +text: .text%__1cJLoadPNodeMstore_Opcode6kM_i_: classes.o; +text: .text%__1cLstoreB0NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cZInterpreterMacroAssemblerbAget_cache_and_index_at_bcp6MpnMRegisterImpl_2i_v_; +text: .text%__1cHTypeAryFxdual6kM_pknEType__; +text: .text%__1cMtlsLoadPNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIVMThreadHexecute6FpnMVM_Operation__v_; +text: .text%__1cCosMget_priority6FkpknGThread_rnOThreadPriority__nIOSReturn__; +text: .text%__1cGThreadMget_priority6Fkpk0_nOThreadPriority__; +text: .text%__1cMVM_OperationIevaluate6M_v_; +text: .text%__1cMVM_OperationSset_calling_thread6MpnGThread_nOThreadPriority__v_; +text: .text%__1cCosTget_native_priority6FkpknGThread_pi_nIOSReturn__; +text: .text%__1cMnegD_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cQcmovI_reg_gtNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cGGCTask2t6Mn0AEKindEkind__v_; +text: .text%__1cNGCTaskManagerVrelease_all_resources6M_v_; +text: .text%__1cLGCTaskQdDueueHenqueue6Mp0_v_; +text: .text%__1cSCardTableExtensionRscavenge_contents6MpnQObjectStartArray_pnMMutableSpace_pnIHeapWord_pnSPSPromotionManager__v_; +text: .text%__1cUWaitForBarrierGCTaskFdo_it6MpnNGCTaskManager_I_v_; +text: .text%__1cNGCTaskManagerIadd_list6MpnLGCTaskQdDueue__v_; +text: .text%__1cHThreadsZcreate_thread_roots_tasks6FpnLGCTaskQdDueue__v_; +text: .text%__1cUWaitForBarrierGCTaskGcreate6F_p0_; +text: .text%__1cUWaitForBarrierGCTaskIdestruct6M_v_; +text: .text%__1cSObjectSynchronizerJfast_exit6FpnHoopDesc_pnJBasicLock_pnGThread__v_; +text: .text%__1cSPSPromotionManagerNpost_scavenge6F_v_; +text: .text%__1cNBarrierGCTaskOdo_it_internal6MpnNGCTaskManager_I_v_; +text: .text%__1cNJvmtiGCMarker2T6M_v_; +text: .text%__1cUWaitForBarrierGCTaskHdestroy6Fp0_v_; +text: .text%__1cLGCTaskQdDueueGcreate6F_p0_; +text: .text%__1cSPSPromotionManagerMpre_scavenge6F_v_; +text: .text%__1cZSerialOldToYoungRootsTaskFdo_it6MpnNGCTaskManager_I_v_; +text: .text%__1cQinstanceRefKlassZacquire_pending_list_lock6FpnJBasicLock__v_; +text: .text%__1cZSerialOldToYoungRootsTaskEname6M_pc_: psTasks.o; +text: .text%__1cKPSYoungGenLswap_spaces6M_v_; +text: .text%__1cUParallelScavengeHeapQresize_young_gen6MII_v_; +text: .text%__1cKPSYoungGenGresize6MII_v_; +text: .text%__1cKPSYoungGenNresize_spaces6MII_v_; +text: .text%__1cSPSPromotionManagerbBvm_thread_promotion_manager6F_p0_; +text: .text%__1cUWaitForBarrierGCTaskIwait_for6M_v_; +text: .text%__1cPVM_GC_OperationNdoit_epilogue6M_v_; +text: .text%__1cNMonitorSupplyHreserve6F_pnHMonitor__; +text: .text%__1cNMonitorSupplyHrelease6FpnHMonitor__v_; +text: .text%__1cUWaitForBarrierGCTaskEname6M_pc_: gcTaskManager.o; +text: .text%__1cTmembar_volatileNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cVLoaderConstraintTableWfind_constrained_klass6MnMsymbolHandle_nGHandle__pnMklassOopDesc__; +text: .text%__1cTloadL_unalignedNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cOcmovII_immNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQComputeCallStackHdo_bool6M_v_: generateOopMap.o; +text: .text%__1cMURShiftLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cSCompiledStaticCallNcompute_entry6FnMmethodHandle_rnOStaticCallInfo__v_; +text: .text%__1cPClassFileParserbJparse_classfile_signature_attribute6MnSconstantPoolHandle_nTinstanceKlassHandle_pnGThread__v_; +text: .text%__1cKstoreBNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSCompiledStaticCallDset6MrknOStaticCallInfo__v_; +text: .text%__1cOGenerateOopMapXreplace_all_CTS_matches6MnNCellTypeState_1_v_; +text: .text%__1cFframeZinterpreter_frame_set_mdp6MpC_v_; +text: .text%__1cZInterpreterMacroAssemblerIpush_ptr6MpnMRegisterImpl__v_; +text: .text%__1cISubLNodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cIciMethodRinterpreter_entry6M_pC_; +text: .text%__1cQmulF_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cPconvF2D_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRcompL_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cJloadBNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%jni_SetBooleanField: jni.o; +text: .text%__1cKimmL13OperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cLcmpF_ccNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cLRuntimeStubbDpreserve_callee_argument_oops6MnFframe_pknLRegisterMap_pnKOopClosure__v_: codeBlob.o; +text: .text%__1cRorI_reg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRsarL_reg_imm6NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQmulI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSInterpreterRuntimeZSignatureHandlerGeneratorLpass_object6M_v_; +text: .text%__1cZInterpreterMacroAssemblerGpush_i6MpnMRegisterImpl__v_; +text: .text%__1cPClassFileParserbBcheck_illegal_static_method6FnTinstanceKlassHandle_pnGThread__v_; +text: .text%__1cLLShiftLNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cQComputeCallStackJdo_double6M_v_: generateOopMap.o; +text: .text%__1cJloadSNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cRloadConP_pollNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNObjectMonitorHRecycle6M_v_; +text: .text%__1cNSharedRuntimeSfind_callee_method6FpnKJavaThread_pnGThread__nMmethodHandle__; +text: .text%__1cMloadConLNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cJloadDNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cQSystemDictionaryTresolve_from_stream6FnMsymbolHandle_nGHandle_2pnPClassFileStream_pnGThread__pnMklassOopDesc__; +text: .text%__1cQstkI_to_regFNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQregP_to_stkPNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cZInterpreterMacroAssemblerFpop_i6MpnMRegisterImpl__v_; +text: .text%__1cIMaxINodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cNSharedRuntimeTreresolve_call_site6FpnKJavaThread_pnGThread__nMmethodHandle__; +text: .text%__1cYcompareAndSwapL_boolNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNSCMemProjNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cYcompareAndSwapL_boolNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cIProjNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cIPSOldGenMmax_gen_size6M_I_: psOldGen.o; +text: .text%__1cKExceptionsK_throw_msg6FpnGThread_pkcipnNsymbolOopDesc_4_v_; +text: .text%__1cSdivL_reg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cbDVM_ParallelGCFailedAllocationEdoit6M_v_; +text: .text%__1cQaddL_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPadd_derived_oop6FppnHoopDesc_2_v_: oopMap.o; +text: .text%__1cMregD_lowOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cHOrINodeIadd_ring6kMpknEType_3_3_; +text: .text%__1cOMethodLivenessKBasicBlockFsplit6Mi_p1_; +text: .text%__1cOcmovII_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cENodeEgetd6kM_d_; +text: .text%__1cOcmovIL_immNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cTAbstractInterpreterSBasicType_as_index6FnJBasicType__i_; +text: .text%__1cZInterpreterMacroAssemblerGpush_f6MpnRFloatRegisterImpl__v_; +text: .text%__1cIciObject2t6MpnHciKlass__v_; +text: .text%__1cPjava_lang_ClassQprimitive_mirror6FnJBasicType__pnHoopDesc__; +text: .text%__1cKExceptionsL_throw_args6FpnGThread_pkcinMsymbolHandle_5pnRJavaCallArguments__v_; +text: .text%__1cPstoreI_FregNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKCMovePNodeGOpcode6kM_i_; +text: .text%__1cLstoreC0NodeIpipeline6kM_pknIPipeline__; +text: .text%JVM_MonitorWait; +text: .text%__1cSObjectSynchronizerEwait6FnGHandle_xpnGThread__v_; +text: .text%__1cIAddLNodeIadd_ring6kMpknEType_3_3_; +text: .text%__1cHciKlass2t6MpnIciSymbol_p0_v_; +text: .text%__1cGciType2t6MpnHciKlass__v_; +text: .text%__1cQshlI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQdivD_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cFParseSjump_if_false_fork6MpnGIfNode_ii_v_; +text: .text%__1cNloadConL0NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cRshrL_reg_imm6NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cUciInstanceKlassKlassEmake6F_p0_; +text: .text%__1cENode2t6Mp0111111_v_; +text: .text%__1cIDivLNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cZInterpreterMacroAssemblerGpush_d6MpnRFloatRegisterImpl__v_; +text: .text%__1cFParseRarray_store_check6M_v_; +text: .text%__1cQsubF_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIciSymbolHbyte_at6Mi_i_; +text: .text%__1cKCompiledICSset_ic_destination6MpC_v_; +text: .text%__1cQaddD_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cCosTset_native_priority6FpnGThread_i_nIOSReturn__; +text: .text%__1cPPerfDataManagerUcreate_long_variable6FnJCounterNS_pkcnIPerfDataFUnits_xpnGThread__pnQPerfLongVariable__; +text: .text%__1cQset_lwp_priority6Fiii_i_; +text: .text%__1cQjava_lang_StringTcreate_oop_from_str6FpkcpnGThread__pnHoopDesc__; +text: .text%jni_NewStringUTF: jni.o; +text: .text%__1cZInterpreterMacroAssemblerGpush_l6MpnMRegisterImpl__v_; +text: .text%__1cQsubI_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cZInterpreterMacroAssemblerXget_constant_pool_cache6MpnMRegisterImpl__v_; +text: .text%__1cSbranchCon_longNodeGnegate6M_v_: ad_sparc_misc.o; +text: .text%__1cKcmpOpUOperKless_equal6kM_i_: ad_sparc_clone.o; +text: .text%__1cPciInstanceKlassNloader_handle6M_pnI_jobject__; +text: .text%__1cPciInstanceKlassYprotection_domain_handle6M_pnI_jobject__; +text: .text%__1cUParallelScavengeHeapIcapacity6kM_I_; +text: .text%__1cNmethodOopDescKjmethod_id6M_pnK_jmethodID__; +text: .text%__1cSsubL_reg_reg_2NodeIpipeline6kM_pknIPipeline__; +text: .text%JVM_DefineClassWithSource; +text: .text%__1cLstoreF0NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%JVM_SetClassSigners; +text: .text%__1cKCompiledICMset_to_clean6M_v_; +text: .text%__1cSandL_reg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cRbranchLoopEndNodeGnegate6M_v_: ad_sparc_misc.o; +text: .text%__1cLRShiftLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cJMarkSweepSFollowStackClosureHdo_void6M_v_: markSweep.o; +text: .text%__1cFParseWcheck_interpreter_type6MpnENode_pknEType_rpnNSafePointNode__2_; +text: .text%__1cOcmovPP_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cSThreadLocalStorageSset_thread_in_slot6FpnGThread__v_; +text: .text%get_thread; +text: .text%__1cKstoreCNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cSThreadLocalStoragebBget_thread_via_cache_slowly6FIi_pnGThread__; +text: .text%__1cSThreadLocalStorageKset_thread6FpnGThread__v_; +text: .text%jni_CallIntMethod: jni.o; +text: .text%__1cSThreadLocalStorageNpd_set_thread6FpnGThread__v_; +text: .text%__1cKloadUBNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSconvD2I_helperNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIMulDNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cSaddP_reg_imm13NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cIAddDNodeGOpcode6kM_i_; +text: .text%__1cOloadI_fregNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOloadI_fregNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cCosJyield_all6Fi_v_; +text: .text%__1cKstoreLNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKstoreLNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPstoreI_FregNodeIpipeline6kM_pknIPipeline__; +text: .text%JVM_GetClassMethodsCount; +text: .text%__1cKstoreINodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%JVM_GetClassFieldsCount; +text: .text%__1cLconvI2BNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%JVM_GetClassCPEntriesCount; +text: .text%JVM_GetClassCPTypes; +text: .text%__1cQmulI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOMacroAssemblerKverify_FPU6Mipkc_v_; +text: .text%__1cbCfind_class_from_class_loader6FpnHJNIEnv__nMsymbolHandle_CnGHandle_3CpnGThread__pnH_jclass__; +text: .text%__1cQjava_lang_ThreadKset_thread6FpnHoopDesc_pnKJavaThread__v_; +text: .text%__1cIAddFNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cQregI_to_stkINodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cQmulF_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cJJavaCallsLcall_static6FpnJJavaValue_nLKlassHandle_nMsymbolHandle_4nGHandle_5pnGThread__v_; +text: .text%__1cXSignatureHandlerLibraryOpd_set_handler6FpC_v_; +text: .text%__1cSInterpreterRuntimeZSignatureHandlerGeneratorIgenerate6MX_v_; +text: .text%JVM_IsPrimitiveClass; +text: .text%__1cJimmU6OperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cOPhaseIdealLoopUpeeled_dom_test_elim6MpnNIdealLoopTree_rnJNode_List__v_; +text: .text%__1cIDivDNodeGOpcode6kM_i_; +text: .text%__1cQsubI_reg_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cLStringTableJbasic_add6MinGHandle_pHiIpnGThread__pnHoopDesc__; +text: .text%__1cIModLNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%jni_FindClass: jni.o; +text: .text%__1cbDjava_lang_reflect_ConstructorTset_exception_types6FpnHoopDesc_2_v_; +text: .text%__1cOMacroAssemblerOstore_argument6MpnMRegisterImpl_rnIArgument__v_: interpreterRT_sparc.o; +text: .text%__1cFParseHdo_irem6M_v_; +text: .text%__1cbDjava_lang_reflect_ConstructorNset_modifiers6FpnHoopDesc_i_v_; +text: .text%__1cbDjava_lang_reflect_ConstructorZset_parameter_annotations6FpnHoopDesc_2_v_; +text: .text%__1cbDjava_lang_reflect_ConstructorPset_annotations6FpnHoopDesc_2_v_; +text: .text%__1cbDjava_lang_reflect_ConstructorIset_slot6FpnHoopDesc_i_v_; +text: .text%__1cbDjava_lang_reflect_ConstructorTset_parameter_types6FpnHoopDesc_2_v_; +text: .text%__1cbDjava_lang_reflect_ConstructorJset_clazz6FpnHoopDesc_2_v_; +text: .text%__1cbDjava_lang_reflect_ConstructorGcreate6FpnGThread__nGHandle__; +text: .text%__1cKReflectionPnew_constructor6FnMmethodHandle_pnGThread__pnHoopDesc__; +text: .text%__1cOcmovII_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSdivL_reg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cTloadL_unalignedNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNSharedRuntimeDd2l6Fd_x_; +text: .text%__1cJStubQdDueueRrequest_committed6Mi_pnEStub__; +text: .text%__1cRInlineCacheBufferRic_stub_code_size6F_i_; +text: .text%__1cFStateP_sub_Op_RShiftL6MpknENode__v_; +text: .text%__1cPICStubInterfaceEsize6kMpnEStub__i_: icBuffer.o; +text: .text%__1cPICStubInterfaceIfinalize6MpnEStub__v_: icBuffer.o; +text: .text%__1cOGenerateOopMapOdo_monitorexit6Mi_v_; +text: .text%__1cJJavaCallsMcall_virtual6FpnJJavaValue_nGHandle_nLKlassHandle_nMsymbolHandle_5pnGThread__v_; +text: .text%__1cQregI_to_stkINodeIpipeline6kM_pknIPipeline__; +text: .text%__1cRorI_reg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOGenerateOopMapLmonitor_pop6M_nNCellTypeState__; +text: .text%__1cMregD_lowOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cLConvD2INodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cSconvI2F_helperNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cHMonitor2T6M_v_; +text: .text%__1cFTypeDFxmeet6kMpknEType__3_; +text: .text%__1cFMutex2T6M_v_; +text: .text%lwp_cond_destroy: os_solaris.o; +text: .text%lwp_mutex_destroy: os_solaris.o; +text: .text%__1cQdivI_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cVcompiledICHolderKlassIoop_size6kMpnHoopDesc__i_; +text: .text%__1cQregP_to_stkPNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQstkI_to_regFNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQregI_to_stkINodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQRelocationHolderEplus6kMi_0_; +text: .text%__1cUPSMarkSweepDecoratorPadjust_pointers6M_v_; +text: .text%__1cUPSMarkSweepDecoratorKprecompact6M_v_; +text: .text%__1cQjava_lang_ThreadLthreadGroup6FpnHoopDesc__2_; +text: .text%__1cHCompileQgrow_alias_types6M_v_; +text: .text%__1cISubLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cOcmovII_immNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cNinstanceKlassKlink_class6MpnGThread__v_; +text: .text%__1cKloadUBNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cTloadD_unalignedNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cJLoadFNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cOloadConL13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRcompL_reg_conNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQaddF_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cICmpDNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cKsplit_once6FpnMPhaseIterGVN_pnENode_333_v_: cfgnode.o; +text: .text%__1cLLShiftLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cJloadFNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cJCMoveNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cOPhaseIdealLoopOdo_range_check6MpnNIdealLoopTree_rnJNode_List__v_; +text: .text%__1cSconvD2I_helperNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cIGraphKitPdstore_rounding6MpnENode__2_; +text: .text%__1cJloadINodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cSdivL_reg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRloadConP_pollNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cIModINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cZCallDynamicJavaDirectNodeKmethod_set6Mi_v_; +text: .text%__1cZCallDynamicJavaDirectNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSconvD2I_helperNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cZCallDynamicJavaDirectNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cUmulL_reg_imm13_1NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQdivL_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cUdivL_reg_imm13_1NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cUmulL_reg_imm13_1NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cUVirtualCallGeneratorIgenerate6MpnIJVMState__2_; +text: .text%__1cNObjectMonitor2t6M_v_; +text: .text%__1cIMulINodeKadd_opcode6kM_i_: classes.o; +text: .text%__1cIMulINodeKmul_opcode6kM_i_: classes.o; +text: .text%__1cQdivD_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJCmpD3NodeGOpcode6kM_i_; +text: .text%__1cJloadDNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cIMinINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cOBasicHashtableJnew_entry6MI_pnTBasicHashtableEntry__; +text: .text%__1cQmulF_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%JVM_MonitorNotify; +text: .text%__1cFBlockNset_next_call6MpnENode_rnJVectorSet_rnLBlock_Array__v_; +text: .text%__1cSObjectSynchronizerGnotify6FnGHandle_pnGThread__v_; +text: .text%__1cXNativeSignatureIteratorJdo_object6Mii_v_: interpreterRT_sparc.o; +text: .text%__1cKstoreFNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cSstring_compareNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRtestI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cVshrL_reg_imm6_L2INodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cYjava_lang_reflect_MethodIset_slot6FpnHoopDesc_i_v_; +text: .text%__1cOloadConL13NodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cYjava_lang_reflect_MethodPset_return_type6FpnHoopDesc_2_v_; +text: .text%__1cYjava_lang_reflect_MethodPset_annotations6FpnHoopDesc_2_v_; +text: .text%__1cYjava_lang_reflect_MethodGcreate6FpnGThread__nGHandle__; +text: .text%__1cINegDNodeGOpcode6kM_i_; +text: .text%__1cYjava_lang_reflect_MethodJset_clazz6FpnHoopDesc_2_v_; +text: .text%__1cYjava_lang_reflect_MethodZset_parameter_annotations6FpnHoopDesc_2_v_; +text: .text%__1cYjava_lang_reflect_MethodWset_annotation_default6FpnHoopDesc_2_v_; +text: .text%__1cYjava_lang_reflect_MethodTset_parameter_types6FpnHoopDesc_2_v_; +text: .text%__1cYjava_lang_reflect_MethodTset_exception_types6FpnHoopDesc_2_v_; +text: .text%__1cYjava_lang_reflect_MethodNset_modifiers6FpnHoopDesc_i_v_; +text: .text%__1cOimmI_32_63OperIconstant6kM_i_: ad_sparc_clone.o; +text: .text%__1cYjava_lang_reflect_MethodIset_name6FpnHoopDesc_2_v_; +text: .text%__1cbFpartialSubtypeCheck_vs_zeroNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cSsubL_reg_reg_2NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOcmovII_regNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cOstackSlotPOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%jni_GetMethodID: jni.o; +text: .text%__1cQshlL_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cIMulINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cNminI_eRegNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cRshlI_reg_imm5NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cOloadConL13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cNObjectMonitorGnotify6MpnGThread__v_; +text: .text%__1cOMacroAssemblerDjmp6MpnMRegisterImpl_ipkci_v_; +text: .text%__1cIDivLNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%JVM_GetClassDeclaredConstructors; +text: .text%__1cUdivL_reg_imm13_1NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKJavaThreadbScheck_safepoint_and_suspend_for_native_trans6Fp0_v_; +text: .text%__1cRInlineCacheBufferVic_buffer_entry_point6FpC_1_; +text: .text%__1cUmulL_reg_imm13_1NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQsubD_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cUdivL_reg_imm13_1NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQregP_to_stkPNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSconvI2F_helperNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRInlineCacheBufferWcreate_transition_stub6FpnKCompiledIC_pnHoopDesc_pC_v_; +text: .text%__1cRInlineCacheBufferXassemble_ic_buffer_code6FpCpnHoopDesc_1_v_; +text: .text%__1cOcmovIF_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQcmovI_reg_ltNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNloadConL0NodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cKo1RegPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cSsubL_reg_reg_1NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIBytecodeIset_code6MnJBytecodesECode__v_; +text: .text%__1cQshrL_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cRsarL_reg_imm6NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cJloadFNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cICodeHeapLfirst_block6kM_pnJHeapBlock__; +text: .text%__1cSInterpreterRuntimeZSignatureHandlerGeneratorIpass_int6M_v_: interpreterRT_sparc.o; +text: .text%__1cRorI_reg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cQshrL_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQshrI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOimmI_32_63OperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cOloadI_fregNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cLConvI2DNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cQjava_lang_ThreadMset_priority6FpnHoopDesc_nOThreadPriority__v_; +text: .text%__1cQdivL_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cKCompiledICKcached_oop6kM_pnHoopDesc__; +text: .text%__1cISubFNodeGOpcode6kM_i_; +text: .text%JVM_IsThreadAlive; +text: .text%__1cXPartialSubtypeCheckNodeGOpcode6kM_i_; +text: .text%__1cLconvI2BNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOcmovIF_immNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cRsarL_reg_imm6NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQaddI_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cRtestI_reg_immNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRtestI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRsubI_zero_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSmulL_reg_reg_1NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cQaddD_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOcmovPI_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKConv2BNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cSstring_compareNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQregL_to_stkLNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cQjava_lang_SystemTout_offset_in_bytes6F_i_; +text: .text%__1cQjava_lang_SystemSin_offset_in_bytes6F_i_; +text: .text%__1cWPredictedCallGeneratorIgenerate6MpnIJVMState__2_; +text: .text%__1cSconvI2F_helperNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNCallGeneratorRfor_uncommon_trap6FpnIciMethod_nODeoptimizationLDeoptReason_n0CLDeoptAction__p0_; +text: .text%__1cOcmovPP_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cZUncommonTrapCallGeneratorIgenerate6MpnIJVMState__2_; +text: .text%__1cbFpartialSubtypeCheck_vs_zeroNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIMulFNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cGThread2t6M_v_; +text: .text%__1cCosHSolarisPhotspot_sigmask6FpnGThread__v_; +text: .text%__1cCosHSolarisVinit_thread_fpu_state6F_v_; +text: .text%__1cFTypeFFxmeet6kMpknEType__3_; +text: .text%__1cCosScurrent_stack_size6F_I_; +text: .text%__1cIOSThreadNpd_initialize6M_v_; +text: .text%__1cCosScurrent_stack_base6F_pC_; +text: .text%__1cIOSThread2t6MpFpv_i1_v_; +text: .text%__1cIMulDNodeImul_ring6kMpknEType_3_3_; +text: .text%__1cCosRinitialize_thread6F_v_; +text: .text%__1cSdivL_reg_reg_1NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cCosPpd_start_thread6FpnGThread__v_; +text: .text%__1cLConvI2FNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cNobjArrayKlassIallocate6MipnGThread__pnPobjArrayOopDesc__; +text: .text%__1cNobjArrayKlassKinitialize6MpnGThread__v_; +text: .text%jni_NewObjectArray: jni.o; +text: .text%__1cSsubL_reg_reg_1NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cOcmovIF_immNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%JVM_SetThreadPriority; +text: .text%__1cCosMstart_thread6FpnGThread__v_; +text: .text%__1cXjava_lang_reflect_FieldNset_modifiers6FpnHoopDesc_i_v_; +text: .text%JVM_GetStackAccessControlContext; +text: .text%__1cXjava_lang_reflect_FieldPset_annotations6FpnHoopDesc_2_v_; +text: .text%__1cFStateM_sub_Op_ModI6MpknENode__v_; +text: .text%JVM_Read; +text: .text%__1cOcmovPI_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cKCompiledICOset_cached_oop6MpnHoopDesc__v_; +text: .text%__1cFStateM_sub_Op_SubL6MpknENode__v_; +text: .text%__1cKCompiledICMstub_address6kM_pC_; +text: .text%__1cJvmSymbolsOsignature_type6FpnNsymbolOopDesc__nJBasicType__; +text: .text%__1cQsubL_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQmodI_reg_regNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cISubDNodeGOpcode6kM_i_; +text: .text%__1cQmodI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPfieldDescriptorLannotations6kM_pnQtypeArrayOopDesc__; +text: .text%__1cRsarI_reg_imm5NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cIGraphKitJpush_pair6MpnENode__v_: callGenerator.o; +text: .text%__1cKReflectionInew_type6FnMsymbolHandle_nLKlassHandle_pnGThread__nGHandle__; +text: .text%__1cXjava_lang_reflect_FieldIset_slot6FpnHoopDesc_i_v_; +text: .text%__1cXjava_lang_reflect_FieldIset_type6FpnHoopDesc_2_v_; +text: .text%__1cXjava_lang_reflect_FieldGcreate6FpnGThread__nGHandle__; +text: .text%__1cXjava_lang_reflect_FieldJset_clazz6FpnHoopDesc_2_v_; +text: .text%__1cXjava_lang_reflect_FieldIset_name6FpnHoopDesc_2_v_; +text: .text%__1cNinstanceKlassYremove_dependent_nmethod6MpnHnmethod__v_; +text: .text%jni_GetStaticFieldID: jni.o; +text: .text%__1cNloadKlassNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cLstoreF0NodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cPciObjArrayKlassEmake6FpnHciKlass__p0_; +text: .text%__1cNinstanceKlassKjni_id_for6Mi_pnFJNIid__; +text: .text%__1cFStateO_sub_Op_CMoveI6MpknENode__v_; +text: .text%__1cENodeEgetf6kM_f_; +text: .text%JVM_DesiredAssertionStatus; +text: .text%__1cKJavaThreadKinitialize6M_v_; +text: .text%__1cWThreadLocalAllocBufferKinitialize6M_v_; +text: .text%__1cLConvL2DNodeGOpcode6kM_i_; +text: .text%__1cQThreadStatistics2t6M_v_; +text: .text%__1cUThreadSafepointStateGcreate6FpnKJavaThread__v_; +text: .text%__1cQshrL_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQsubD_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cGThreadFstart6Fp0_v_; +text: .text%__1cOMacroAssemblerIround_to6MpnMRegisterImpl_i_v_: interp_masm_sparc.o; +text: .text%__1cPconvI2D_memNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%jni_GetFloatArrayRegion: jni.o; +text: .text%__1cJMarkSweepMfollow_stack6F_v_; +text: .text%__1cNimmP_pollOperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cRtestI_reg_immNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cJMemRegionMintersection6kMk0_0_; +text: .text%__1cKJavaThread2t6MpFp0pnGThread__vI_v_; +text: .text%__1cKJavaThreadDrun6M_v_; +text: .text%__1cNSafepointBlobHoops_do6MpnKOopClosure__v_: codeBlob.o; +text: .text%__1cPjava_lang_ClassOprimitive_type6FpnHoopDesc__nJBasicType__; +text: .text%JVM_IsArrayClass; +text: .text%jni_CallStaticVoidMethod: jni.o; +text: .text%__1cPPerfDataManagerTcreate_long_counter6FnJCounterNS_pkcnIPerfDataFUnits_xpnGThread__pnPPerfLongCounter__; +text: .text%__1cLConvF2DNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cNsymbolOopDescWas_klass_external_name6kM_pkc_; +text: .text%__1cHnmethodbDpreserve_callee_argument_oops6MnFframe_pknLRegisterMap_pnKOopClosure__v_; +text: .text%__1cKstoreBNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cFKlassNexternal_name6kM_pkc_; +text: .text%__1cOGenerateOopMapYrewrite_refval_conflicts6M_v_; +text: .text%__1cKstoreLNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cOGenerateOopMapKinterp_all6M_v_; +text: .text%__1cOGenerateOopMapPinitialize_vars6M_v_; +text: .text%__1cTloadD_unalignedNodeIpipeline6kM_pknIPipeline__; +text: .text%JVM_GetClassName; +text: .text%__1cOloadI_fregNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cOGenerateOopMapbAmake_context_uninitialized6M_v_; +text: .text%__1cOGenerateOopMapKinit_state6M_v_; +text: .text%__1cOGenerateOopMapYsetup_method_entry_state6M_v_; +text: .text%__1cOGenerateOopMapTmark_reachable_code6M_v_; +text: .text%__1cOGenerateOopMapRinit_basic_blocks6M_v_; +text: .text%__1cLStringTableGintern6FpkcpnGThread__pnHoopDesc__; +text: .text%__1cOcmovIF_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cCosMset_priority6FpnGThread_nOThreadPriority__nIOSReturn__; +text: .text%__1cLConvD2INodeJideal_reg6kM_I_: classes.o; +text: .text%__1cOcmovIL_immNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cXNativeSignatureIteratorGdo_int6M_v_: interpreterRT_sparc.o; +text: .text%__1cINodeHashEgrow6M_v_; +text: .text%__1cOGenerateOopMapPdo_monitorenter6Mi_v_; +text: .text%__1cOcmovPP_regNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cMloadConDNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cIMaxINodeIadd_ring6kMpknEType_3_3_; +text: .text%__1cJloadSNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cOGenerateOopMapLcompute_map6MpnGThread__v_; +text: .text%__1cLConvF2DNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%JVM_Open; +text: .text%__1cRInvocationCounterFreset6M_v_; +text: .text%__1cRCompilationPolicybIreset_counter_for_invocation_event6MnMmethodHandle__v_; +text: .text%__1cOGenerateOopMap2t6MnMmethodHandle__v_; +text: .text%__1cOGenerateOopMapRdo_interpretation6M_v_; +text: .text%__1cIRetTableRcompute_ret_table6MnMmethodHandle__v_; +text: .text%__1cOGenerateOopMapMmonitor_push6MnNCellTypeState__v_; +text: .text%__1cOGenerateOopMapNinitialize_bb6M_v_; +text: .text%__1cOGenerateOopMapbImark_bbheaders_and_count_gc_points6M_v_; +text: .text%__1cSmulL_reg_reg_1NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSdivL_reg_reg_1NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cZInterpreterMacroAssemblerEpush6MnITosState__v_; +text: .text%JVM_StartThread; +text: .text%__1cMthread_entry6FpnKJavaThread_pnGThread__v_: jvm.o; +text: .text%jni_GetStaticObjectField: jni.o; +text: .text%__1cJArrayDataKcell_count6M_i_: ciMethodData.o; +text: .text%__1cIGraphKitSprecision_rounding6MpnENode__2_; +text: .text%__1cNPerfByteArray2t6MnJCounterNS_pkcnIPerfDataFUnits_n0CLVariability_i_v_; +text: .text%__1cIGraphKitRcreate_and_map_if6MpnENode_2ff_pnGIfNode__: generateOptoStub.o; +text: .text%__1cQjava_lang_ThreadIpriority6FpnHoopDesc__nOThreadPriority__; +text: .text%__1cQjava_lang_ThreadJstackSize6FpnHoopDesc__x_; +text: .text%__1cMLinkResolverYresolve_interface_method6FrnMmethodHandle_rnLKlassHandle_nSconstantPoolHandle_ipnGThread__v_; +text: .text%__1cKJavaThreadHprepare6MpnI_jobject_nOThreadPriority__v_; +text: .text%__1cTLoadD_unalignedNodeGOpcode6kM_i_; +text: .text%__1cQshrI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%JVM_FreeMemory; +text: .text%__1cVcompiledICHolderKlassToop_follow_contents6MpnHoopDesc__v_; +text: .text%JVM_TotalMemory; +text: .text%__1cVcompiledICHolderKlassToop_adjust_pointers6MpnHoopDesc__i_; +text: .text%__1cMloadConDNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQdivL_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOcmovIL_immNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cPconvI2D_memNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cSandL_reg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cHThreadsGremove6FpnKJavaThread__v_; +text: .text%__1cIOSThread2T6M_v_; +text: .text%__1cUThreadSafepointStateHdestroy6FpnKJavaThread__v_; +text: .text%__1cKJavaThreadYremove_stack_guard_pages6M_v_; +text: .text%__1cQandI_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cQjava_lang_ThreadNset_stillborn6FpnHoopDesc__v_; +text: .text%__1cRInterpreterOopMapNresource_copy6MpnQOopMapCacheEntry__v_; +text: .text%__1cLConvD2INodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cIOSThreadKpd_destroy6M_v_; +text: .text%__1cWstatic_call_RelocationLstatic_stub6M_pC_; +text: .text%__1cKJavaThread2T6M_v_; +text: .text%__1cGThread2T5B6M_v_; +text: .text%__1cCosLfree_thread6FpnIOSThread__v_; +text: .text%__1cFStateM_sub_Op_MulI6MpknENode__v_; +text: .text%__1cNThreadServiceWcurrent_thread_exiting6FpnKJavaThread__v_; +text: .text%__1cLensure_join6FpnKJavaThread__v_: thread.o; +text: .text%__1cQOopMapCacheEntryEfill6MnMmethodHandle_i_v_; +text: .text%__1cSTailCalljmpIndNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOGenerateOopMapEppop6MpnNCellTypeState__v_; +text: .text%__1cSTailCalljmpIndNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQsubF_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cRNativeMovConstRegEdata6kM_i_; +text: .text%__1cbFunnecessary_membar_volatileNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cLcmpF_ccNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cNObjectMonitorJnotifyAll6MpnGThread__v_; +text: .text%jni_CallObjectMethod: jni.o; +text: .text%__1cQaddD_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cPconvD2F_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cRInlineCacheBufferUic_buffer_cached_oop6FpC_pnHoopDesc__; +text: .text%__1cQdivD_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cZInterpreterMacroAssemblerbEset_method_data_pointer_offset6MpnMRegisterImpl__v_; +text: .text%__1cIMaxINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cQChunkPoolCleanerEtask6M_v_: allocation.o; +text: .text%__1cHTypeInt2t6Miii_v_; +text: .text%__1cTOopMapForCacheEntryLcompute_map6MpnGThread__v_; +text: .text%__1cOcmovIL_immNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cKConv2BNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cSandL_reg_imm13NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cNloadRangeNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cRshlI_reg_imm5NodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cSInterpreterRuntimeZSignatureHandlerGeneratorJpass_long6M_v_; +text: .text%__1cQregL_to_stkLNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cOGenerateOopMapVresult_for_basicblock6Mi_v_; +text: .text%__1cXNativeSignatureIteratorHdo_long6M_v_: interpreterRT_sparc.o; +text: .text%__1cQOopMapCacheEntryIset_mask6MpnNCellTypeState_2i_v_; +text: .text%__1cLOptoRuntimeYcurrent_time_millis_Type6F_pknITypeFunc__; +text: .text%__1cHTypePtrFxdual6kM_pknEType__; +text: .text%__1cOstackSlotIOperFindex6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cOstackSlotIOperEdisp6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%JVM_MonitorNotifyAll; +text: .text%__1cJloadDNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOstackSlotIOperEbase6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cKCMoveLNodeGOpcode6kM_i_; +text: .text%__1cRshlL_reg_imm6NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cMnegD_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cODeoptimizationVtrap_state_has_reason6Fii_i_; +text: .text%__1cTloadD_unalignedNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cJloadDNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cNiRegIsafeOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cNloadConP0NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cSinstanceKlassKlassOklass_oop_size6kM_i_: instanceKlassKlass.o; +text: .text%__1cIAddDNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cMnegD_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSandL_reg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPmethodDataKlassOklass_oop_size6kM_i_: methodDataKlass.o; +text: .text%__1cKarrayKlassWuncached_lookup_method6kMpnNsymbolOopDesc_2_pnNmethodOopDesc__; +text: .text%__1cLmethodKlassOklass_oop_size6kM_i_: methodKlass.o; +text: .text%__1cKarrayKlassWcompute_modifier_flags6kMpnGThread__i_; +text: .text%__1cWconstantPoolCacheKlassOklass_oop_size6kM_i_: cpCacheKlass.o; +text: .text%__1cQconstMethodKlassOklass_oop_size6kM_i_: constMethodKlass.o; +text: .text%__1cXJNI_ArgumentPusherVaArgJget_float6M_v_: jni.o; +text: .text%__1cKklassKlassOklass_oop_size6kM_i_: arrayKlassKlass.o; +text: .text%__1cSobjArrayKlassKlassOklass_oop_size6kM_i_: objArrayKlassKlass.o; +text: .text%__1cLsymbolKlassOklass_oop_size6kM_i_: symbolKlass.o; +text: .text%__1cVcompiledICHolderKlassOklass_oop_size6kM_i_: compiledICHolderKlass.o; +text: .text%__1cSsubL_reg_reg_1NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSmulL_reg_reg_1NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSdivL_reg_reg_1NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRconstantPoolKlassOklass_oop_size6kM_i_: constantPoolKlass.o; +text: .text%__1cTtypeArrayKlassKlassOklass_oop_size6kM_i_: typeArrayKlassKlass.o; +text: .text%__1cOloadI_fregNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRtestI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQjava_lang_ThreadbGinherited_access_control_context6FpnHoopDesc__2_; +text: .text%__1cJLoadSNodeMstore_Opcode6kM_i_: classes.o; +text: .text%__1cLstoreF0NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIMinINodeIadd_ring6kMpknEType_3_3_; +text: .text%JVM_GetInheritedAccessControlContext; +text: .text%__1cPPerfDataManagerWcreate_string_constant6FnJCounterNS_pkc3pnGThread__pnSPerfStringConstant__; +text: .text%__1cNmaxI_eRegNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%JVM_NativePath; +text: .text%__1cOMacroAssemblerNflush_windows6M_v_; +text: .text%__1cSsubD_regD_regDNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cVCallRuntimeDirectNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cFJNIidHoops_do6MpnKOopClosure__v_; +text: .text%__1cJHashtableHoops_do6MpnKOopClosure__v_; +text: .text%__1cHCompileKinit_start6MpnJStartNode__v_; +text: .text%__1cKg3RegPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cVinline_cache_regPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cKstorePNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cQObjectStartArrayFreset6M_v_; +text: .text%__1cPconvI2D_memNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cHThreadsHoops_do6FpnKOopClosure__v_; +text: .text%__1cQaddD_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLConvF2INodeGOpcode6kM_i_; +text: .text%__1cVCallRuntimeDirectNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cJHashtableGunlink6MpnRBoolObjectClosure__v_; +text: .text%__1cIPSOldGenPadjust_pointers6M_v_; +text: .text%__1cVCallRuntimeDirectNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cOcmovPI_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cIPSOldGenHcompact6M_v_; +text: .text%__1cMtlsLoadPNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cLcmpF_ccNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cVCallRuntimeDirectNodeKmethod_set6Mi_v_; +text: .text%__1cKimmI11OperIconstant6kM_i_: ad_sparc_clone.o; +text: .text%__1cQcmovI_reg_gtNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cLstoreP0NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cOcmovIF_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cOcmovLL_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%jni_GetStaticMethodID: jni.o; +text: .text%__1cZInterpreterMacroAssemblerUupdate_mdp_by_offset6MipnMRegisterImpl__v_; +text: .text%__1cRtestI_reg_immNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cHnmethodbAmake_not_entrant_or_zombie6Mi_v_; +text: .text%__1cPconvF2D_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOPhaseIdealLoopKdo_peeling6MpnNIdealLoopTree_rnJNode_List__v_; +text: .text%__1cOcmovLL_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%jint_cmp: parse2.o; +text: .text%__1cXjava_lang_boxing_objectJget_value6FpnHoopDesc_pnGjvalue__nJBasicType__; +text: .text%__1cNloadConL0NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOMacroAssemblerKnull_check6MpnMRegisterImpl_i_v_; +text: .text%__1cVMoveL2D_stack_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cIMulDNodeGmul_id6kM_pknEType__: classes.o; +text: .text%__1cIGraphKitTdprecision_rounding6MpnENode__2_; +text: .text%__1cOcmovLL_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cLConvD2FNodeGOpcode6kM_i_; +text: .text%__1cIMulFNodeImul_ring6kMpknEType_3_3_; +text: .text%__1cWloadConI_x41f00000NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKcmpOpFOperFccode6kM_i_: ad_sparc_clone.o; +text: .text%__1cLstoreC0NodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cQregL_to_stkLNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cZregDHi_regDLo_to_regDNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOcmovIF_immNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cOcmovDF_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cQaddL_reg_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cZregDHi_regDLo_to_regDNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%JVM_Close; +text: .text%__1cSmulD_regD_regDNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cQsubL_reg_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cIMulDNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cKstoreFNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSsubD_regD_regDNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSaddD_regD_regDNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSaddP_reg_imm13NodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cXconvI2D_regDHi_regDNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cKstoreFNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPPerfDataManagerUcreate_long_constant6FnJCounterNS_pkcnIPerfDataFUnits_xpnGThread__pnQPerfLongConstant__; +text: .text%__1cOMacroAssemblerNget_vm_result6MpnMRegisterImpl__v_; +text: .text%__1cQsubF_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cZInterpreterMacroAssemblerbIcompute_extra_locals_size_in_bytes6MpnMRegisterImpl_22_v_; +text: .text%__1cLcmpF_ccNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPMultiBranchDataScompute_cell_count6FpnOBytecodeStream__i_; +text: .text%__1cPorI_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cSxorI_reg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPconvI2D_memNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cQdivI_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cLconvI2BNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cISubFNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cWloadConI_x43300000NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cWloadConI_x41f00000NodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSmulI_reg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOtailjmpIndNodeNis_block_proj6kM_pknENode__: ad_sparc_misc.o; +text: .text%__1cRInlineCacheBufferSic_destination_for6FpnKCompiledIC__pC_; +text: .text%__1cbFunnecessary_membar_volatileNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cJSubFPNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cFParseNdo_instanceof6M_v_; +text: .text%__1cLconvI2BNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cIGraphKitOgen_instanceof6MpnENode_2_2_; +text: .text%__1cbFunnecessary_membar_volatileNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cRshrL_reg_imm6NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cJloadBNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cQdivI_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIDivLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cLConvI2DNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cSmulD_regD_regDNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOstackSlotLOperEdisp6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cKConv2BNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cQshlI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cXjava_lang_reflect_FieldFclazz6FpnHoopDesc__2_; +text: .text%__1cXjava_lang_reflect_FieldJmodifiers6FpnHoopDesc__i_; +text: .text%__1cJloadDNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOcmovPP_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQsubF_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%jni_NewObjectV: jni.o; +text: .text%__1cOcmovLI_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cPciInstanceKlassLjava_mirror6M_pnKciInstance__; +text: .text%__1cCosHSolarisKmmap_chunk6FpcIii_2_; +text: .text%__1cXPartialSubtypeCheckNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%jni_EnsureLocalCapacity; +text: .text%__1cLstoreI0NodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cIAddFNodeIIdentity6MpnOPhaseTransform__pnENode__: classes.o; +text: .text%__1cLConvD2INodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cKoopFactoryUnew_compiledICHolder6FnMmethodHandle_nLKlassHandle_pnGThread__pnXcompiledICHolderOopDesc__; +text: .text%__1cSCompiledStaticCallMset_to_clean6M_v_; +text: .text%__1cIDivDNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cVcompiledICHolderKlassIallocate6MpnGThread__pnXcompiledICHolderOopDesc__; +text: .text%__1cbFpartialSubtypeCheck_vs_zeroNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cSaddD_regD_regDNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cPfieldDescriptorUdouble_initial_value6kM_d_; +text: .text%__1cQsubD_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cOcmovPP_regNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cNSafePointNodeQpeek_monitor_obj6kM_pnENode__; +text: .text%__1cJloadFNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cSaddI_reg_imm13NodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cFParsePdo_monitor_exit6M_v_; +text: .text%__1cObranchConFNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cObranchConFNodeJlabel_set6MrnFLabel_I_v_; +text: .text%__1cSconvF2I_helperNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cSmembar_releaseNodeIadr_type6kM_pknHTypePtr__; +text: .text%__1cObranchConFNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cLcmpD_ccNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cJloadLNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cISubDNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cZInterpreterMacroAssemblerUprofile_taken_branch6MpnMRegisterImpl_2_v_; +text: .text%__1cLResourceObj2n6FIn0APallocation_type__pv_; +text: .text%__1cNSafePointNodeQpeek_monitor_box6kM_pnENode__; +text: .text%__1cFTypeFFxdual6kM_pknEType__; +text: .text%__1cICmpFNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cKVtableStubRpd_code_alignment6F_i_; +text: .text%__1cKarrayKlassYcompute_secondary_supers6MipnGThread__pnPobjArrayOopDesc__; +text: .text%__1cKloadUBNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cTloadL_unalignedNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cINegDNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cLConvI2FNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cOcmovLL_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRorI_reg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cTloadL_unalignedNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cTloadL_unalignedNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cKloadUBNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cXconvI2D_regDHi_regDNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cZInterpreterMacroAssemblerbFtest_invocation_counter_for_mdp6MpnMRegisterImpl_22rnFLabel__v_; +text: .text%__1cXconvI2D_regDHi_regDNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSvframeArrayElementHfill_in6MpnOcompiledVFrame__v_; +text: .text%__1cFTypeDFxdual6kM_pknEType__; +text: .text%__1cSaddD_regD_regDNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cZInterpreterMacroAssemblerbAincrement_backedge_counter6MpnMRegisterImpl_2_v_; +text: .text%__1cZInterpreterMacroAssemblerbBtest_backedge_count_for_osr6MpnMRegisterImpl_22_v_; +text: .text%__1cSmulL_reg_imm13NodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cOcmovPI_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKEntryPoint2t6M_v_; +text: .text%__1cTloadD_unalignedNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cZregDHi_regDLo_to_regDNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOcompiledVFrameImonitors6kM_pnNGrowableArray4CpnLMonitorInfo____; +text: .text%__1cOcompiledVFrameLexpressions6kM_pnUStackValueCollection__; +text: .text%__1cHciKlassOsuper_of_depth6MI_p0_; +text: .text%__1cOcompiledVFrameGlocals6kM_pnUStackValueCollection__; +text: .text%__1cOcompiledVFrameGmethod6kM_pnNmethodOopDesc__; +text: .text%__1cJimmP0OperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cOcompiledVFrameHraw_bci6kM_i_; +text: .text%__1cQshrI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cWloadConI_x43300000NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cHThreadsbMis_supported_jni_version_including_1_16Fi_C_; +text: .text%__1cMTailJumpNodeKmatch_edge6kMI_I_; +text: .text%__1cWloadConI_x41f00000NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cODeoptimizationbJupdate_method_data_from_interpreter6FnQmethodDataHandle_ii_v_; +text: .text%__1cIimmDOperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cFframeZinterpreter_frame_set_mdx6Mi_v_; +text: .text%__1cOstackSlotLOperFindex6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cOstackSlotLOperEbase6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cTloadD_unalignedNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cIModLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cOtailjmpIndNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cSmulD_regD_regDNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cINegFNodeGOpcode6kM_i_; +text: .text%__1cSsubD_regD_regDNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cJScopeDescImonitors6M_pnNGrowableArray4CpnMMonitorValue____; +text: .text%__1cJScopeDescLexpressions6M_pnNGrowableArray4CpnKScopeValue____; +text: .text%__1cJScopeDescGlocals6M_pnNGrowableArray4CpnKScopeValue____; +text: .text%JVM_GetComponentType; +text: .text%__1cQdivI_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%Unsafe_DefineClass1; +text: .text%__1cOcmovII_immNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cLvframeArrayPunpack_to_stack6MrnFframe_i_v_; +text: .text%__1cKReflectionUarray_component_type6FpnHoopDesc_pnGThread__2_; +text: .text%__1cLConvF2DNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cSvframeArrayElementDbci6kM_i_; +text: .text%__1cVMoveF2I_stack_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%JVM_GetCPFieldModifiers; +text: .text%__1cKJavaThreadbFdeoptimized_wrt_marked_nmethods6M_v_; +text: .text%__1cNnmethodLocker2t6MpC_v_; +text: .text%__1cNSharedRuntimebJcontinuation_for_implicit_exception6FpnKJavaThread_pCn0AVImplicitExceptionKind__3_; +text: .text%__1cODeoptimizationNuncommon_trap6FpnKJavaThread_i_pn0ALUnrollBlock__; +text: .text%__1cODeoptimizationTuncommon_trap_inner6FpnKJavaThread_i_v_; +text: .text%__1cODeoptimizationNunpack_frames6FpnKJavaThread_i_nJBasicType__; +text: .text%__1cODeoptimizationYfetch_unroll_info_helper6FpnKJavaThread__pn0ALUnrollBlock__; +text: .text%__1cZInterpreterMacroAssemblerXindex_check_without_pop6MpnMRegisterImpl_2i22_v_; +text: .text%__1cRSignatureIteratorKparse_type6M_i_; +text: .text%__1cPconvD2F_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cHciKlassLjava_mirror6M_pnKciInstance__; +text: .text%__1cODeoptimizationRlast_frame_adjust6Fii_i_; +text: .text%__1cQsubD_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%JVM_DefineClass; +text: .text%JVM_InvokeMethod; +text: .text%__1cOcmovPP_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%jni_NewDirectByteBuffer; +text: .text%__1cHJNIEnv_JNewObject6MpnH_jclass_pnK_jmethodID_E_pnI_jobject__: jni.o; +text: .text%jni_AllocObject: jni.o; +text: .text%__1cNTemplateTableMlocals_index6FpnMRegisterImpl_i_v_; +text: .text%__1cTmembar_volatileNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cMnegD_regNodeIpipeline6kM_pknIPipeline__; +text: .text%Unsafe_AllocateInstance; +text: .text%__1cQComputeCallStackHdo_byte6M_v_: generateOopMap.o; +text: .text%__1cQstkI_to_regINodeIpipeline6kM_pknIPipeline__; +text: .text%__1cYjava_lang_reflect_MethodEslot6FpnHoopDesc__i_; +text: .text%__1cYjava_lang_reflect_MethodFclazz6FpnHoopDesc__2_; +text: .text%__1cYinternal_word_RelocationGtarget6M_pC_; +text: .text%__1cJStubQdDueueKremove_all6M_v_; +text: .text%__1cMloadConFNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cPconvI2D_memNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cPorL_reg_regNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cZInterpreterMacroAssemblerLindex_check6MpnMRegisterImpl_2i22_v_; +text: .text%__1cJJavaCallsMcall_virtual6FpnJJavaValue_nGHandle_nLKlassHandle_nMsymbolHandle_533pnGThread__v_; +text: .text%__1cSaddL_reg_imm13NodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cOcmovPI_regNodeLbottom_type6kM_pknEType__: ad_sparc_misc.o; +text: .text%__1cKstfSSFNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cMloadConFNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cKReflectionNinvoke_method6FpnHoopDesc_nGHandle_nOobjArrayHandle_pnGThread__2_; +text: .text%__1cYjava_lang_reflect_MethodPparameter_types6FpnHoopDesc__2_; +text: .text%__1cTmembar_volatileNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPconvI2L_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cOcmovII_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cYjava_lang_reflect_MethodLreturn_type6FpnHoopDesc__2_; +text: .text%__1cJCmpF3NodeGOpcode6kM_i_; +text: .text%__1cLMoveL2DNodeGOpcode6kM_i_; +text: .text%__1cFKlassWcompute_modifier_flags6kMpnGThread__i_; +text: .text%__1cKReflectionRreflect_new_array6FpnHoopDesc_ipnGThread__pnMarrayOopDesc__; +text: .text%__1cOcmovII_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIAddFNodeJideal_reg6kM_I_: classes.o; +text: .text%JVM_NewArray; +text: .text%__1cHOrLNodeGOpcode6kM_i_; +text: .text%__1cLStrCompNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cLOopMapCache2t6M_v_; +text: .text%__1cNTemplateTableHconvert6F_v_; +text: .text%__1cOcmovDF_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cZInterpreterMacroAssemblerFpop_l6MpnMRegisterImpl__v_; +text: .text%__1cOcmovLI_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cSMachBreakpointNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSInterpreterRuntimeQcreate_exception6FpnKJavaThread_pc3_v_; +text: .text%__1cQComputeCallStackIdo_array6Mii_v_: generateOopMap.o; +text: .text%__1cKPSYoungGenKprecompact6M_v_; +text: .text%__1cXjava_lang_reflect_FieldEslot6FpnHoopDesc__i_; +text: .text%__1cSconvD2I_helperNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cMnegF_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cHThreadsLgc_prologue6F_v_; +text: .text%__1cHThreadsLgc_epilogue6F_v_; +text: .text%__1cPconvI2L_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cPconvD2I_regNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cJJavaCallsLcall_static6FpnJJavaValue_nLKlassHandle_nMsymbolHandle_4nGHandle_pnGThread__v_; +text: .text%__1cUParallelScavengeHeapHcollect6MnHGCCauseFCause__v_; +text: .text%__1cRCardTableModRefBSFclear6MnJMemRegion__v_; +text: .text%__1cVLoaderConstraintTableYpurge_loader_constraints6MpnRBoolObjectClosure__v_; +text: .text%__1cVLoaderConstraintTableYalways_strong_classes_do6MpnKOopClosure__v_; +text: .text%__1cLconvP2BNodeMideal_Opcode6kM_i_: ad_sparc_misc.o; +text: .text%__1cQSystemDictionaryValways_strong_oops_do6FpnKOopClosure__v_; +text: .text%__1cIciMethodVget_osr_flow_analysis6Mi_pnKciTypeFlow__; +text: .text%__1cLMoveF2INodeGOpcode6kM_i_; +text: .text%__1cKNativeJumpUpatch_verified_entry6FpC11_v_; +text: .text%__1cMStartOSRNodeKosr_domain6F_pknJTypeTuple__; +text: .text%__1cVVM_ParallelGCSystemGCEdoit6M_v_; +text: .text%__1cJArgumentsQPropertyList_add6FppnOSystemProperty_2_v_; +text: .text%__1cOMacroAssemblerPbreakpoint_trap6M_v_; +text: .text%__1cJBasicLockHmove_to6MpnHoopDesc_p0_v_; +text: .text%__1cJMarkSweepNrestore_marks6F_v_; +text: .text%__1cJMarkSweepMadjust_marks6F_v_; +text: .text%__1cJMarkSweepXfollow_weak_klass_links6F_v_; +text: .text%__1cRStubCodeGeneratorLstub_epilog6MpnMStubCodeDesc__v_; +text: .text%__1cMStubCodeMark2t6MpnRStubCodeGenerator_pkc4_v_; +text: .text%__1cMStubCodeMark2T6M_v_; +text: .text%__1cNCallGeneratorHfor_osr6FpnIciMethod_i_p0_; +text: .text%__1cLClassLoaderSget_system_package6FpkcpnGThread__pnHoopDesc__; +text: .text%__1cJPSPermGenKprecompact6M_v_; +text: .text%JVM_GC; +text: .text%__1cIPSOldGenKprecompact6M_v_; +text: .text%__1cUPSMarkSweepDecoratorbIset_destination_decorator_perm_gen6F_v_; +text: .text%__1cUPSMarkSweepDecoratorbHset_destination_decorator_tenured6F_v_; +text: .text%__1cKDictionaryYalways_strong_classes_do6MpnKOopClosure__v_; +text: .text%__1cQmulL_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cUPSAdaptiveSizePolicyUmajor_collection_end6MInHGCCauseFCause__v_; +text: .text%__1cUPSAdaptiveSizePolicyWmajor_collection_begin6M_v_; +text: .text%__1cIUniverseWupdate_heap_info_at_gc6F_v_; +text: .text%__1cJPSPermGenQcompute_new_size6MI_v_; +text: .text%__1cKPSYoungGenHcompact6M_v_; +text: .text%JVM_GetSystemPackage; +text: .text%__1cPfieldDescriptorTfloat_initial_value6kM_f_; +text: .text%__1cKPSYoungGenPadjust_pointers6M_v_; +text: .text%__1cQUncommonTrapBlobHoops_do6MpnKOopClosure__v_: codeBlob.o; +text: .text%__1cSDeoptimizationBlobHoops_do6MpnKOopClosure__v_: codeBlob.o; +text: .text%__1cNExceptionBlobHoops_do6MpnKOopClosure__v_: codeBlob.o; +text: .text%__1cJCodeCacheHoops_do6FpnKOopClosure__v_; +text: .text%__1cJCodeCacheLgc_prologue6F_v_; +text: .text%__1cJCodeCacheLgc_epilogue6F_v_; +text: .text%__1cIXorINodeIadd_ring6kMpknEType_3_3_; +text: .text%__1cbFpartialSubtypeCheck_vs_zeroNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cQregL_to_stkLNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cKcmpOpFOperKless_equal6kM_i_: ad_sparc_clone.o; +text: .text%__1cOcmovPI_regNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cSmulL_reg_imm13NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cOcmovIF_immNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cKCMoveDNodeGOpcode6kM_i_; +text: .text%__1cJLoadDNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cIMulFNodeGmul_id6kM_pknEType__: classes.o; +text: .text%__1cNStubGeneratorLstub_prolog6MpnMStubCodeDesc__v_: stubGenerator_sparc.o; +text: .text%__1cQaddL_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%jni_GetStringRegion: jni.o; +text: .text%JVM_RawMonitorCreate; +text: .text%__1cJloadLNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cIMulFNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cNinstanceKlassPadd_osr_nmethod6MpnHnmethod__v_; +text: .text%__1cOstackSlotPOperEbase6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cOstackSlotPOperFindex6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cOstackSlotPOperEdisp6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cZInterpreterMacroAssemblerNunlock_object6MpnMRegisterImpl__v_; +text: .text%JVM_Sleep; +text: .text%__1cLConvL2DNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cQstkI_to_regFNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQinstanceRefKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: instanceRefKlass.o; +text: .text%__1cRorI_reg_imm13NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%Unsafe_CompareAndSwapInt; +text: .text%JVM_Lseek; +text: .text%__1cNloadRangeNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cPconvD2F_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cRComputeEntryStackJdo_object6Mii_v_: generateOopMap.o; +text: .text%__1cPconvF2D_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cQmulI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQmulF_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cMnegF_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cSconvF2I_helperNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cQmulD_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOcmovLI_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cPMultiBranchDataPpost_initialize6MpnOBytecodeStream_pnRmethodDataOopDesc__v_; +text: .text%__1cQregP_to_stkPNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cZInterpreterMacroAssemblerQtest_mdp_data_at6MipnMRegisterImpl_rnFLabel_2_v_; +text: .text%__1cQstkI_to_regINodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cOcmovLI_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cGciType2t6MnJBasicType__v_; +text: .text%__1cJLoadBNodeMstore_Opcode6kM_i_: classes.o; +text: .text%__1cQaddF_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cETypeEmake6Fn0AFTYPES__pk0_; +text: .text%__1cSconvF2I_helperNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cRsarL_reg_imm6NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSstring_compareNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%jni_GetEnv; +text: .text%__1cJloadDNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cQstkI_to_regINodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cSstring_compareNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cXNativeSignatureIteratorHdo_bool6M_v_: interpreterRT_sparc.o; +text: .text%Unsafe_GetNativeByte; +text: .text%JVM_NanoTime; +text: .text%__1cCosNjavaTimeNanos6F_x_; +text: .text%__1cOMacroAssemblerOrestore_thread6MkpnMRegisterImpl__v_; +text: .text%__1cVcompiledICHolderKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cQandL_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cIimmFOperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cHThreadsLnmethods_do6F_v_; +text: .text%__1cKcmpOpFOperGnegate6M_v_: ad_sparc_clone.o; +text: .text%__1cICodeBlobFflush6M_v_; +text: .text%__1cFParseMdo_anewarray6M_v_; +text: .text%__1cSdivL_reg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%jni_CallVoidMethod: jni.o; +text: .text%__1cJCodeCacheFfirst6F_pnICodeBlob__; +text: .text%__1cObranchConFNodeGnegate6M_v_: ad_sparc_misc.o; +text: .text%__1cFParseOdo_tableswitch6M_v_; +text: .text%__1cOcmovIF_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLConvI2FNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cSaddL_reg_imm13NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cLstoreC0NodeLout_RegMask6kM_rknHRegMask__; +text: .text%Unsafe_GetNativeFloat; +text: .text%__1cOstackSlotFOperEtype6kM_pknEType__: ad_sparc.o; +text: .text%__1cHnmethodFflush6M_v_; +text: .text%__1cHnmethodSflush_dependencies6MpnRBoolObjectClosure__v_; +text: .text%__1cKo2RegPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cQregI_to_stkINodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cbCAbstractInterpreterGeneratorVgenerate_method_entry6MnTAbstractInterpreterKMethodKind__pC_; +text: .text%__1cParrayKlassKlassRoop_copy_contents6MpnSPSPromotionManager_pnHoopDesc__v_; +text: .text%__1cFVTuneOdelete_nmethod6FpnHnmethod__v_; +text: .text%__1cWloadConI_x43300000NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cFParseQdo_monitor_enter6M_v_; +text: .text%__1cPorL_reg_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cLstoreC0NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%JVM_FindPrimitiveClass; +text: .text%__1cVMoveL2D_stack_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cNTemplateTableEiop26Fn0AJOperation__v_; +text: .text%__1cZInterpreterMacroAssemblerMdispatch_via6MnITosState_ppC_v_; +text: .text%__1cSmodL_reg_imm13NodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cRshrI_reg_imm5NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cJJavaCallsLcall_static6FpnJJavaValue_nLKlassHandle_nMsymbolHandle_4pnGThread__v_; +text: .text%__1cSsubL_reg_reg_2NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cUmulL_reg_imm13_1NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cIDivDNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cPconvI2F_regNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cNinstanceKlassUfind_interface_field6kMpnNsymbolOopDesc_2pnPfieldDescriptor__pnMklassOopDesc__; +text: .text%__1cOstackSlotFOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cUdivL_reg_imm13_1NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cRSignatureIteratorHiterate6M_v_; +text: .text%__1cOcmovLL_regNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cJname2type6Fpkc_nJBasicType__; +text: .text%__1cSmulL_reg_imm13NodeIpipeline6kM_pknIPipeline__; +text: .text%__1cPBytecode_invokeLresult_type6kMpnGThread__nJBasicType__; +text: .text%__1cOloadConL13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cKcmpOpFOperHgreater6kM_i_: ad_sparc_clone.o; +text: .text%__1cIDivDNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cOMacroAssemblerKget_thread6M_v_; +text: .text%__1cOcmovDF_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cOcmovIF_immNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cSconvI2F_helperNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cKVtableStub2n6FIi_pv_; +text: .text%__1cbEJvmtiDynamicCodeEventCollector2T6M_v_; +text: .text%__1cOtypeArrayKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: typeArrayKlass.o; +text: .text%__1cPconvD2F_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cIciMethodMnative_entry6M_pC_; +text: .text%__1cVMoveF2I_stack_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cPPerfDataManagerWcreate_string_variable6FnJCounterNS_pkci3pnGThread__pnSPerfStringVariable__; +text: .text%__1cPorL_reg_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cPconvD2F_regNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cIciSymbolHas_utf86M_pkc_; +text: .text%__1cQandI_reg_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cQciTypeArrayKlass2t6MnLKlassHandle__v_; +text: .text%__1cMnegD_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cFStateO_sub_Op_CMoveP6MpknENode__v_; +text: .text%__1cQmulD_reg_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cOMacroAssemblerZtotal_frame_size_in_bytes6Mi_i_; +text: .text%__1cNTemplateTableQfast_accessfield6FnITosState__v_; +text: .text%__1cKCompiledICSset_to_megamorphic6MpnICallInfo_nJBytecodesECode_pnGThread__v_; +text: .text%Unsafe_StaticFieldOffset; +text: .text%__1cQmulI_reg_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cNTemplateTableXresolve_cache_and_index6FipnMRegisterImpl_2_v_; +text: .text%__1cQaddI_reg_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cOcmovLI_regNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%JVM_GetClassContext; +text: .text%Unsafe_StaticFieldBaseFromField; +text: .text%Unsafe_EnsureClassInitialized; +text: .text%__1cOcmovIF_regNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cOMacroAssemblerMcall_VM_leaf6MpnMRegisterImpl_pCi_v_; +text: .text%__1cNTemplateTableZjvmti_post_fast_field_mod6F_v_; +text: .text%Unsafe_GetObjectVolatile; +text: .text%__1cbEJvmtiDynamicCodeEventCollector2t6M_v_; +text: .text%__1cKstoreFNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cVMoveL2D_stack_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cJLoadLNodeMstore_Opcode6kM_i_: classes.o; +text: .text%__1cNSharedRuntimeVhandle_ic_miss_helper6FpnKJavaThread_pnGThread__nMmethodHandle__; +text: .text%__1cOloadConL13NodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cNTemplateTablePfast_storefield6FnITosState__v_; +text: .text%__1cLstoreF0NodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cPconvI2D_memNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cETypeFxdual6kM_pk0_; +text: .text%__1cJOopMapSetQsingular_oop_map6M_pnGOopMap__; +text: .text%__1cKimmU13OperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cZInterpreterMacroAssemblerTnotify_method_entry6M_v_; +text: .text%__1cZInterpreterMacroAssemblerbCincrement_invocation_counter6MpnMRegisterImpl_2_v_; +text: .text%__1cZInterpreterMacroAssemblerQaccess_local_int6MpnMRegisterImpl_2_v_; +text: .text%__1cZInterpreterMacroAssemblerWempty_expression_stack6M_v_; +text: .text%__1cUInterpreterGeneratorVgenerate_counter_incr6MpnFLabel_22_v_; +text: .text%__1cOcmovIL_immNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPPerfDataManagerKname_space6Fpkci_pc_; +text: .text%__1cOtailjmpIndNodePoper_input_base6kM_I_: ad_sparc_misc.o; +text: .text%__1cNMemoryManagerIadd_pool6MpnKMemoryPool__v_; +text: .text%__1cCosEstat6FpkcpnEstat__i_; +text: .text%__1cQregF_to_stkINodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cRComputeEntryStackIdo_short6M_v_: generateOopMap.o; +text: .text%__1cRComputeEntryStackGdo_int6M_v_: generateOopMap.o; +text: .text%__1cMMonitorChunk2t6Mi_v_; +text: .text%__1cQSystemDictionaryPresolve_or_null6FnMsymbolHandle_pnGThread__pnMklassOopDesc__; +text: .text%__1cOPhaseIdealLoopJclone_iff6MpnHPhiNode_pnNIdealLoopTree__pnIBoolNode__; +text: .text%__1cQComputeCallStackIdo_float6M_v_: generateOopMap.o; +text: .text%__1cMMonitorValue2t6MpnTDebugInfoReadStream__v_; +text: .text%__1cPciObjArrayKlassJmake_impl6FpnHciKlass__p0_; +text: .text%__1cPorL_reg_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cLOptoRuntimeMrethrow_Type6F_pknITypeFunc__; +text: .text%jni_SetStaticObjectField: jni.o; +text: .text%jni_RegisterNatives: jni.o; +text: .text%__1cFframebLprevious_monitor_in_interpreter_frame6kMpnPBasicObjectLock__2_; +text: .text%__1cQshlL_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%JVM_GetClassDeclaredFields; +text: .text%__1cCosMuser_handler6F_pv_; +text: .text%JVM_IsSameClassPackage; +text: .text%__1cKMemoryPoolLadd_manager6MpnNMemoryManager__v_; +text: .text%__1cKJavaThreadRadd_monitor_chunk6MpnMMonitorChunk__v_; +text: .text%__1cKJavaThreadUremove_monitor_chunk6MpnMMonitorChunk__v_; +text: .text%__1cVMoveL2D_stack_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNTemplateTableGiconst6Fi_v_; +text: .text%__1cLConvF2INodeLbottom_type6kM_pknEType__: classes.o; +text: .text%JVM_LoadLibrary; +text: .text%JVM_IsSupportedJNIVersion; +text: .text%Unsafe_ObjectFieldOffset; +text: .text%__1cZInterpreterMacroAssemblerYtest_method_data_pointer6MrnFLabel__v_; +text: .text%__1cNTemplateTableHif_0cmp6Fn0AJCondition__v_; +text: .text%__1cZInterpreterMacroAssemblerSget_cpool_and_tags6MpnMRegisterImpl_2_v_; +text: .text%__1cIAddDNodeIIdentity6MpnOPhaseTransform__pnENode__: classes.o; +text: .text%__1cNTemplateTableHif_icmp6Fn0AJCondition__v_; +text: .text%__1cNTemplateTableH_return6FnITosState__v_; +text: .text%__1cHOrLNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cKimmP13OperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cLConvD2FNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cSObjectSynchronizerJjni_enter6FnGHandle_pnGThread__v_; +text: .text%__1cHnmethodbJcontinuation_for_implicit_exception6MpC_1_; +text: .text%__1cNSharedRuntimeEdrem6Fdd_d_; +text: .text%__1cPstoreI_FregNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cTloadD_unalignedNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cOloadI_fregNodeOmemory_operand6kM_pknIMachOper__; +text: .text%__1cLconvP2BNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cCosZvm_allocation_granularity6F_i_; +text: .text%__1cMTailJumpNodeGOpcode6kM_i_; +text: .text%__1cTloadD_unalignedNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cHciKlass2t6MnLKlassHandle_pnIciSymbol__v_; +text: .text%__1cJMemRegion2t6M_v_: cardTableModRefBS.o; +text: .text%__1cSObjectSynchronizerIjni_exit6FpnHoopDesc_pnGThread__v_; +text: .text%__1cNRegisterSaverWrestore_live_registers6FpnOMacroAssembler__v_; +text: .text%__1cLTypeInstPtrOxmeet_unloaded6kMpk0_2_; +text: .text%__1cRtestI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPPerfLongVariant2t6MnJCounterNS_pkcnIPerfDataFUnits_n0CLVariability_pnUPerfLongSampleHelper__v_; +text: .text%__1cWImplicitExceptionTable2t6MpknHnmethod__v_; +text: .text%__1cWImplicitExceptionTableCat6kMI_I_; +text: .text%__1cFParseVcatch_call_exceptions6MrnYciExceptionHandlerStream__v_; +text: .text%jni_GetJavaVM; +text: .text%__1cOcmovDF_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%jni_MonitorEnter: jni.o; +text: .text%jni_MonitorExit: jni.o; +text: .text%__1cLConvL2DNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cULinearLeastSquareFit2t6MI_v_; +text: .text%__1cQdivL_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cPciObjectFactoryTget_unloaded_method6MpnPciInstanceKlass_pnIciSymbol_4_pnIciMethod__; +text: .text%__1cNReservedSpace2t6MI_v_; +text: .text%__1cSCardTableExtensionVresize_covered_region6MnJMemRegion__v_; +text: .text%__1cOloadI_fregNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cRCardTableModRefBSVresize_covered_region6MnJMemRegion__v_; +text: .text%__1cIAddDNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cJloadFNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cKConv2BNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cLConvI2DNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cSconvD2I_helperNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%jni_Throw: jni.o; +text: .text%__1cNTemplateTableHcall_VM6FpnMRegisterImpl_pC_v_; +text: .text%__1cLMoveL2DNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cIDivINodeJideal_reg6kM_I_: classes.o; +text: .text%__1cISubDNodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cPstoreI_FregNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cINegFNodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cOLibraryCallKitXgenerate_current_thread6MrpnENode__2_; +text: .text%__1cOMacroAssemblerEfneg6MnRFloatRegisterImplFWidth_p13_v_; +text: .text%__1cXNativeSignatureIteratorJdo_double6M_v_: interpreterRT_sparc.o; +text: .text%__1cRtestI_reg_immNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNSpaceCounters2t6MpkciIpnMMutableSpace_pnSGenerationCounters__v_; +text: .text%__1cLcmpF_ccNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cMNativeLookupTbase_library_lookup6Fpkc22_pC_; +text: .text%jni_SetObjectField: jni.o; +text: .text%__1cPPerfDataManagerUcreate_long_variable6FnJCounterNS_pkcnIPerfDataFUnits_pnUPerfLongSampleHelper_pnGThread__pnQPerfLongVariable__; +text: .text%__1cPPerfDataManagerKname_space6Fpkc2i_pc_; +text: .text%bootstrap_flush_windows; +text: .text%__1cSdivL_reg_reg_1NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cZInterpreterMacroAssemblerbCverify_oop_or_return_address6MpnMRegisterImpl_2_v_; +text: .text%__1cFStateO_sub_Op_Conv2B6MpknENode__v_; +text: .text%__1cNRegisterSaverTsave_live_registers6FpnOMacroAssembler_ipi_pnGOopMap__; +text: .text%__1cSmulL_reg_reg_1NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQJNI_FastGetFieldbCgenerate_fast_get_int_field06FnJBasicType__pC_; +text: .text%__1cKExceptionsK_throw_oop6FpnGThread_pkcipnHoopDesc__v_; +text: .text%__1cSsubL_reg_reg_1NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSInterpreterRuntimeZSignatureHandlerGeneratorLpass_double6M_v_; +text: .text%__1cQmulD_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%Unsafe_AllocateMemory; +text: .text%__1cSandL_reg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%JVM_GetLastErrorString; +text: .text%__1cQmodL_reg_regNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cNTemplateTableElop26Fn0AJOperation__v_; +text: .text%__1cQjava_lang_ThreadKset_daemon6FpnHoopDesc__v_; +text: .text%__1cNTemplateTableEfop26Fn0AJOperation__v_; +text: .text%__1cPstoreI_FregNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cNTemplateTableEdop26Fn0AJOperation__v_; +text: .text%__1cSandI_reg_imm13NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cMnegD_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNciMethodKlassEmake6F_p0_; +text: .text%__1cNTemplateTableGlstore6Fi_v_; +text: .text%__1cLConvF2INodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cIciMethod2t6MpnPciInstanceKlass_pnIciSymbol_4_v_; +text: .text%__1cRcompL_reg_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cLconvI2BNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cLConvD2FNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cSconvD2I_helperNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cRsubI_zero_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cKstfSSFNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cOClassPathEntry2t6M_v_; +text: .text%__1cZInterpreterMacroAssemblerQaccess_local_ptr6MpnMRegisterImpl_2_v_; +text: .text%__1cNTemplateTableGistore6Fi_v_; +text: .text%__1cIRetTableUfind_jsrs_for_target6Mi_pnNRetTableEntry__; +text: .text%__1cPconvL2I_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cUcompI_iReg_imm13NodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cRsarI_reg_imm5NodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cNTemplateTableGastore6Fi_v_; +text: .text%__1cIRetTableHadd_jsr6Mii_v_; +text: .text%__1cMnegF_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cQregF_to_stkINodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cRComputeEntryStackHdo_bool6M_v_: generateOopMap.o; +text: .text%__1cNTemplateTableGdstore6Fi_v_; +text: .text%__1cNTemplateTableGfstore6Fi_v_; +text: .text%jni_CallStaticObjectMethod: jni.o; +text: .text%__1cOcmovLL_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cLconvI2BNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cODeoptimizationLUnrollBlockOsize_of_frames6kM_i_; +text: .text%__1cCosGsignal6Fipv_1_; +text: .text%__1cQaddD_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cISubDNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cISubFNodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cISubFNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cNTemplateTableFlload6Fi_v_; +text: .text%__1cNTemplateTableFiload6Fi_v_; +text: .text%__1cMOopMapStream2t6MpnGOopMap_i_v_; +text: .text%__1cLconvP2BNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cVMoveF2I_stack_regNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cOMacroAssemblerMcall_VM_leaf6MpnMRegisterImpl_pC22_v_; +text: .text%__1cOMacroAssemblerMcall_VM_leaf6MpnMRegisterImpl_pC2_v_; +text: .text%__1cTjava_lang_ThrowableLset_message6FpnHoopDesc_2_v_; +text: .text%__1cOGenerateOopMapTret_jump_targets_do6MpnOBytecodeStream_pFp0ipi_vi4_v_; +text: .text%__1cPconvI2D_regNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%Unsafe_SetMemory; +text: .text%__1cKstfSSFNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cZInterpreterMacroAssemblerOthrow_if_not_x6MnJAssemblerJCondition_pCpnMRegisterImpl__v_; +text: .text%__1cVMoveF2I_stack_regNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cHTypePtrKadd_offset6kMi_pk0_; +text: .text%__1cOcmovLI_regNodeHsize_of6kM_I_: ad_sparc_misc.o; +text: .text%__1cNloadConL0NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cOcmovPI_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cOcmovDF_regNodeHtwo_adr6kM_I_: ad_sparc_misc.o; +text: .text%__1cQsubF_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cFParseRjump_if_true_fork6MpnGIfNode_ii_v_; +text: .text%__1cZInterpreterMacroAssemblerQthrow_if_not_icc6MnJAssemblerJCondition_pCpnMRegisterImpl__v_; +text: .text%__1cNTemplateTableFfload6Fi_v_; +text: .text%__1cFParsePdo_lookupswitch6M_v_; +text: .text%__1cNTemplateTableFdload6Fi_v_; +text: .text%__1cKstfSSFNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cINegDNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cNTemplateTableFaload6Fi_v_; +text: .text%__1cRMachSpillCopyNodeHsize_of6kM_I_: ad_sparc.o; +text: .text%__1cQCompilerCounters2t6MpkcipnGThread__v_; +text: .text%__1cOGenerateOopMapRdo_multianewarray6Mii_v_; +text: .text%__1cNCompileBrokerUcompiler_thread_loop6F_v_; +text: .text%__1cbFpartialSubtypeCheck_vs_zeroNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%jni_CallStaticObjectMethodV: jni.o; +text: .text%__1cNTemplateTableMfast_xaccess6FnITosState__v_; +text: .text%__1cJMemRegionFminus6kMk0_0_; +text: .text%__1cNCompileBrokerUmake_compiler_thread6FpkcpnMCompileQdDueue_pnQCompilerCounters_pnGThread__pnOCompilerThread__; +text: .text%__1cSInterpreterRuntimebKthrow_ArrayIndexOutOfBoundsException6FpnKJavaThread_pci_v_; +text: .text%__1cNMemoryManager2t6M_v_; +text: .text%__1cFStatebB_sub_Op_PartialSubtypeCheck6MpknENode__v_; +text: .text%__1cFStateM_sub_Op_DivI6MpknENode__v_; +text: .text%__1cUPSGenerationCounters2t6MpkciipnOPSVirtualSpace__v_; +text: .text%__1cCosFyield6F_v_; +text: .text%__1cQsubD_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cXNativeSignatureIteratorIdo_float6M_v_: interpreterRT_sparc.o; +text: .text%__1cIDivDNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cFParseRdo_multianewarray6M_v_; +text: .text%__1cLOptoRuntimeTmultianewarray_Type6Fi_pknITypeFunc__; +text: .text%__1cZInterpreterMacroAssemblerRget_constant_pool6MpnMRegisterImpl__v_; +text: .text%__1cXPartialSubtypeCheckNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cOcmovIF_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cLMoveF2INodeLbottom_type6kM_pknEType__: classes.o; +text: .text%__1cSconvI2D_helperNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cLstoreF0NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cZInterpreterMacroAssemblerLlock_object6MpnMRegisterImpl_2_v_; +text: .text%__1cPstoreI_FregNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cOcmovLL_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cZInterpreterMacroAssemblerUupdate_mdp_by_offset6MpnMRegisterImpl_i2_v_; +text: .text%__1cNSafepointBlobGcreate6FpnKCodeBuffer_pnJOopMapSet_i_p0_; +text: .text%__1cMciArrayKlassRbase_element_type6M_pnGciType__; +text: .text%JVM_GetInterfaceVersion; +text: .text%__1cZInterpreterMacroAssemblerRgen_subtype_check6MpnMRegisterImpl_2222rnFLabel__v_; +text: .text%__1cbFpartialSubtypeCheck_vs_zeroNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNTemplateTableGfconst6Fi_v_; +text: .text%__1cGThreadbFinitialize_thread_local_storage6M_v_; +text: .text%__1cOcmovPI_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cGThreadbArecord_stack_base_and_size6M_v_; +text: .text%__1cNTemplateTableHcall_VM6FpnMRegisterImpl_pC2_v_; +text: .text%JVM_RegisterSignal; +text: .text%JVM_FindSignal; +text: .text%__1cTMaskFillerForNative2t6MnMmethodHandle_pIi_v_: oopMapCache.o; +text: .text%jio_vsnprintf; +text: .text%__1cQshrL_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cZInterpreterMacroAssemblerTprofile_switch_case6MpnMRegisterImpl_222_v_; +text: .text%__1cOCompilerThread2t6MpnMCompileQdDueue_pnQCompilerCounters__v_; +text: .text%__1cOPSVirtualSpace2t6MnNReservedSpace_I_v_; +text: .text%__1cVcompiler_thread_entry6FpnKJavaThread_pnGThread__v_: thread.o; +text: .text%__1cNIdealLoopTreeUmerge_many_backedges6MpnOPhaseIdealLoop__v_; +text: .text%__1cODeoptimizationLUnrollBlock2T6M_v_; +text: .text%jni_GetDoubleArrayRegion: jni.o; +text: .text%__1cMLinkResolverbBlookup_method_in_interfaces6FrnMmethodHandle_nLKlassHandle_nMsymbolHandle_4pnGThread__v_; +text: .text%__1cLconvP2BNodeErule6kM_I_: ad_sparc_misc.o; +text: .text%__1cKfix_parent6FpnNIdealLoopTree_1_v_: loopnode.o; +text: .text%JVM_Available; +text: .text%__1cZInterpreterMacroAssemblerSprofile_final_call6MpnMRegisterImpl__v_; +text: .text%__1cQshlL_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cZInterpreterMacroAssemblerQtop_most_monitor6M_nHAddress__; +text: .text%__1cLstoreF0NodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cZInterpreterMacroAssemblerWprofile_switch_default6MpnMRegisterImpl__v_; +text: .text%__1cTAbstract_VM_VersionOvm_info_string6F_pkc_; +text: .text%__1cJStubQdDueue2t6MpnNStubInterface_ipnFMutex_pkc_v_; +text: .text%__1cSconvF2I_helperNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cHThreadsbFdeoptimized_wrt_marked_nmethods6F_v_; +text: .text%__1cbAconvL2D_reg_slow_fxtofNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cOstackSlotFOperEdisp6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cOstackSlotFOperEbase6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cOstackSlotFOperFindex6kMpnNPhaseRegAlloc_pknENode_i_i_: ad_sparc.o; +text: .text%__1cPconvF2I_regNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cNTemplateTableGlconst6Fi_v_; +text: .text%__1cLstoreC0NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cMPeriodicTaskGenroll6M_v_; +text: .text%__1cMPeriodicTask2t6MI_v_; +text: .text%__1cNTemplateTableHcastore6F_v_; +text: .text%Unsafe_CompareAndSwapObject; +text: .text%__1cLNamedThread2t6M_v_; +text: .text%__1cLNamedThreadIset_name6MpkcE_v_; +text: .text%__1cJloadDNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQdivD_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cWloadConI_x43300000NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNTemplateTableKinitialize6F_v_; +text: .text%__1cKcmpOpFOperJnot_equal6kM_i_: ad_sparc_clone.o; +text: .text%__1cPconvD2F_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNTemplateTableKdouble_cmp6Fi_v_; +text: .text%__1cNTemplateTableJfloat_cmp6Fi_v_; +text: .text%__1cNTemplateTableHcall_VM6FpnMRegisterImpl_pC22_v_; +text: .text%__1cNTemplateTableGdconst6Fi_v_; +text: .text%__1cSconvF2I_helperNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOcmovIF_immNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOcmovIF_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cJimmL0OperJnum_edges6kM_I_: ad_sparc_clone.o; +text: .text%__1cSaddD_regD_regDNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cSsubD_regD_regDNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQregF_to_stkINodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cNTemplateTableTinvokevfinal_helper6FpnMRegisterImpl_2_v_; +text: .text%__1cSmulD_regD_regDNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cNTemplateTableUgenerate_vtable_call6FpnMRegisterImpl_22_v_; +text: .text%__1cNTemplateTableKif_nullcmp6Fn0AJCondition__v_; +text: .text%__1cNTemplateTableHif_acmp6Fn0AJCondition__v_; +text: .text%__1cNVM_DeoptimizeEdoit6M_v_; +text: .text%__1cMnegF_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQsubL_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cMVirtualSpace2t6M_v_; +text: .text%__1cWloadConI_x41f00000NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQdivI_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cZregDHi_regDLo_to_regDNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cXconvI2D_regDHi_regDNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cKloadUBNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cNTemplateTableEidiv6F_v_; +text: .text%__1cQstkI_to_regINodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cLMoveL2DNodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cLConvD2FNodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cLConvF2INodeIIdentity6MpnOPhaseTransform__pnENode__; +text: .text%__1cQJNI_FastGetFieldbEgenerate_fast_get_float_field06FnJBasicType__pC_; +text: .text%__1cLMoveF2INodeFValue6kMpnOPhaseTransform__pknEType__; +text: .text%__1cLOptoRuntimeIl2f_Type6F_pknITypeFunc__; +text: .text%__1cOMacroAssemblerUcalc_mem_param_words6MpnMRegisterImpl_2_v_; +text: .text%__1cZInterpreterMacroAssemblerLprofile_ret6MnITosState_pnMRegisterImpl_3_v_; +text: .text%__1cZInterpreterMacroAssemblerUprofile_virtual_call6MpnMRegisterImpl_2_v_; +text: .text%__1cZInterpreterMacroAssemblerMprofile_call6MpnMRegisterImpl__v_; +text: .text%__1cLklassVtableQindex_of_miranda6MpnNsymbolOopDesc_2_i_; +text: .text%__1cZInterpreterMacroAssemblerSupdate_mdp_for_ret6MnITosState_pnMRegisterImpl__v_; +text: .text%__1cMLinkResolverbEvtable_index_of_miranda_method6FnLKlassHandle_nMsymbolHandle_2pnGThread__i_; +text: .text%__1cUInterpreterGeneratorLlock_method6M_v_; +text: .text%__1cZInterpreterMacroAssemblerOthrow_if_not_26MpCpnMRegisterImpl_rnFLabel__v_; +text: .text%__1cZInterpreterMacroAssemblerQthrow_if_not_1_x6MnJAssemblerJCondition_rnFLabel__v_; +text: .text%__1cZInterpreterMacroAssemblerZget_4_byte_integer_at_bcp6MipnMRegisterImpl_2n0AKsetCCOrNot__v_; +text: .text%__1cCosHrealloc6FpvI_1_; +text: .text%__1cODeoptimizationVdeoptimize_dependents6F_i_; +text: .text%__1cFStateO_sub_Op_CMoveL6MpknENode__v_; +text: .text%__1cZInterpreterMacroAssemblerRaccess_local_long6MpnMRegisterImpl_2_v_; +text: .text%__1cIPSOldGenPinitialize_work6Mpkci_v_; +text: .text%__1cCosIjvm_path6Fpci_v_; +text: .text%__1cCosNsigexitnum_pd6F_i_; +text: .text%__1cCosScurrent_process_id6F_i_; +text: .text%__1cINegFNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cSInterpreterRuntimeMat_safepoint6FpnKJavaThread__v_; +text: .text%__1cLConvL2DNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cLConvF2INodeJideal_reg6kM_I_: classes.o; +text: .text%__1cLConvD2FNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cKJNIHandlesQmake_weak_global6FnGHandle__pnI_jobject__; +text: .text%__1cZInterpreterMacroAssemblerSaccess_local_float6MpnMRegisterImpl_pnRFloatRegisterImpl__v_; +text: .text%__1cZInterpreterMacroAssemblerTaccess_local_double6MpnMRegisterImpl_pnRFloatRegisterImpl__v_; +text: .text%__1cZInterpreterMacroAssemblerPstore_local_int6MpnMRegisterImpl_2_v_; +text: .text%__1cZInterpreterMacroAssemblerQstore_local_long6MpnMRegisterImpl_2_v_; +text: .text%__1cZInterpreterMacroAssemblerRstore_local_float6MpnMRegisterImpl_pnRFloatRegisterImpl__v_; +text: .text%__1cZInterpreterMacroAssemblerSstore_local_double6MpnMRegisterImpl_pnRFloatRegisterImpl__v_; +text: .text%__1cCosWactive_processor_count6F_i_; +text: .text%__1cTAbstractInterpreterKinitialize6F_v_; +text: .text%jni_NewWeakGlobalRef: jni.o; +text: .text%__1cRComputeEntryStackIdo_array6Mii_v_: generateOopMap.o; +text: .text%__1cTMaskFillerForNativeLpass_object6M_v_: oopMapCache.o; +text: .text%__1cOGenerateOopMapTadd_to_ref_init_set6Mi_v_; +text: .text%__1cUGcThreadCountClosureJdo_thread6MpnGThread__v_; +text: .text%__1cNinstanceKlassSremove_osr_nmethod6MpnHnmethod__v_; +text: .text%__1cOPSVirtualSpace2t6M_v_; +text: .text%jni_IsInstanceOf: jni.o; +text: .text%__1cMGCTaskThreadDrun6M_v_; +text: .text%__1cJCodeCachebGmake_marked_nmethods_not_entrant6F_v_; +text: .text%__1cTMaskFillerForNativeJpass_long6M_v_: oopMapCache.o; +text: .text%jni_CallStaticVoidMethodV: jni.o; +text: .text%jni_CallStaticBooleanMethod: jni.o; +text: .text%__1cMGCTaskThread2t6MpnNGCTaskManager_II_v_; +text: .text%__1cOtailjmpIndNodeIpipeline6kM_pknIPipeline__; +text: .text%__1cMGCTaskThreadFstart6M_v_; +text: .text%__1cQObjectStartArrayKinitialize6MnJMemRegion__v_; +text: .text%__1cQObjectStartArraySset_covered_region6MnJMemRegion__v_; +text: .text%__1cZInterpreterMacroAssemblerbAdispatch_next_noverify_oop6MnITosState_i_v_; +text: .text%__1cRCollectorCounters2t6Mpkci_v_; +text: .text%__1cFParseDl2f6M_v_; +text: .text%__1cPGCMemoryManagerXinitialize_gc_stat_info6M_v_; +text: .text%__1cJArgumentsVset_parallel_gc_flags6F_v_; +text: .text%__1cPGCMemoryManager2t6M_v_; +text: .text%__1cRComputeEntryStackHdo_long6M_v_: generateOopMap.o; +text: .text%__1cSInterpreterRuntimeWcreate_klass_exception6FpnKJavaThread_pcpnHoopDesc__v_; +text: .text%__1cQcreate_os_thread6FpnGThread_I_pnIOSThread__: os_solaris.o; +text: .text%__1cYjava_lang_reflect_MethodPcompute_offsets6F_v_; +text: .text%__1cSInterpreterRuntimeSupdate_mdp_for_ret6FpnKJavaThread_i_v_; +text: .text%__1cPorL_reg_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQjava_lang_ThreadPcompute_offsets6F_v_; +text: .text%__1cXNativeSignatureIteratorHdo_byte6M_v_: interpreterRT_sparc.o; +text: .text%__1cCosHSolarisQsignal_sets_init6F_v_; +text: .text%__1cCosbDallocate_thread_local_storage6F_i_; +text: .text%__1cUInterpreterGeneratorVrestore_native_result6M_v_; +text: .text%__1cVjava_lang_ThreadGroupPcompute_offsets6F_v_; +text: .text%__1cLconvP2BNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cVshrL_reg_imm6_L2INodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cJJavaCallsMcall_special6FpnJJavaValue_nGHandle_nLKlassHandle_nMsymbolHandle_5pnGThread__v_; +text: .text%__1cCosGstrdup6Fpkc_pc_; +text: .text%__1cCosLinit_random6Fl_v_; +text: .text%__1cUInterpreterGeneratorXgenerate_accessor_entry6M_pC_; +text: .text%__1cCosXterminate_signal_thread6F_v_; +text: .text%__1cCosLsignal_init6F_v_; +text: .text%__1cTsignal_thread_entry6FpnKJavaThread_pnGThread__v_: os.o; +text: .text%__1cOtailjmpIndNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cUInterpreterGeneratorUgenerate_empty_entry6M_pC_; +text: .text%__1cUInterpreterGenerator2t6MpnJStubQdDueue__v_; +text: .text%__1cCosbDinit_system_properties_values6F_v_; +text: .text%__1cCosPphysical_memory6F_X_; +text: .text%__1cHvm_exit6Fi_v_; +text: .text%__1cLbefore_exit6FpnKJavaThread__v_; +text: .text%__1cbCAbstractInterpreterGeneratorbFgenerate_slow_signature_handler6M_pC_; +text: .text%__1cSThreadLocalStorageHpd_init6F_v_; +text: .text%__1cVMoveF2I_stack_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cVMoveL2D_stack_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cWinvocationCounter_init6F_v_; +text: .text%__1cKTypeOopPtrEmake6FnHTypePtrDPTR_i_pk0_; +text: .text%__1cKTypeOopPtrFxdual6kM_pknEType__; +text: .text%__1cFParseMjump_if_join6MpnENode_2_2_; +text: .text%__1cSinstanceKlassKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cSinstanceKlassKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: instanceKlassKlass.o; +text: .text%__1cLconvP2BNodeGExpand6MpnFState_rnJNode_List__pnIMachNode__; +text: .text%__1cETypeRInitialize_shared6FpnHCompile__v_; +text: .text%__1cQinstanceRefKlassZupdate_nonstatic_oop_maps6FpnMklassOopDesc__v_; +text: .text%__1cVInterfaceSupport_init6F_v_; +text: .text%__1cZInterpreterMacroAssemblerSsuper_call_VM_leaf6MpnMRegisterImpl_pC2_v_; +text: .text%__1cPGenerationSizerQinitialize_flags6M_v_: parallelScavengeHeap.o; +text: .text%__1cZInterpreterMacroAssemblerPdispatch_normal6MnITosState__v_; +text: .text%__1cJTimeStampMmilliseconds6kM_x_; +text: .text%__1cDhpiZinitialize_socket_library6F_i_; +text: .text%__1cDhpiYinitialize_get_interface6FpnIvm_calls__v_; +text: .text%__1cWInlineCacheBuffer_init6F_v_; +text: .text%__1cWThreadLocalAllocBufferWstartup_initialization6F_v_; +text: .text%__1cPGlobalTLABStats2t6M_v_; +text: .text%__1cLicache_init6F_v_; +text: .text%__1cSThreadLocalStorageEinit6F_v_; +text: .text%__1cNThreadServiceEinit6F_v_; +text: .text%__1cTICacheStubGeneratorVgenerate_icache_flush6MppFpCii_i_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: indexSet.o; +text: .text%__1cPvm_init_globals6F_v_; +text: .text%__1cMinit_globals6F_i_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: ad_sparc_expand.o; +text: .text%__1cMexit_globals6F_v_; +text: .text%__1cSset_init_completed6F_v_; +text: .text%__1cNinstanceKlassZrelease_C_heap_structures6M_v_; +text: .text%__1cJTimeStampJupdate_to6Mx_v_; +text: .text%__1cUParallelScavengeHeapItop_addr6kM_ppnIHeapWord__: parallelScavengeHeap.o; +text: .text%__1cCosHSolarisXinstall_signal_handlers6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: interp_masm_sparc.o; +text: .text%__1cQinterpreter_init6F_v_; +text: .text%__1cbCAbstractInterpreterGenerator2t6MpnJStubQdDueue__v_; +text: .text%__1cRlwp_priocntl_init6F_i_: os_solaris.o; +text: .text%__1cNpriocntl_stub6FinGidtype_lipc_l_: os_solaris.o; +text: .text%__1cbCAbstractInterpreterGeneratorMgenerate_all6M_v_; +text: .text%__1cCosLsignal_wait6F_i_; +text: .text%__1cCosNsignal_notify6Fi_v_; +text: .text%__1cCosOsignal_init_pd6F_v_; +text: .text%__1cCosHSolarisPinit_signal_mem6F_v_; +text: .text%__1cCosSget_temp_directory6F_pkc_; +text: .text%__1cCosHSolarisOlibthread_init6F_v_; +text: .text%__1cUParallelScavengeHeapIend_addr6kM_ppnIHeapWord__: parallelScavengeHeap.o; +text: .text%__1cUParallelScavengeHeapEheap6F_p0_; +text: .text%__1cUParallelScavengeHeapNgc_threads_do6kMpnNThreadClosure__v_; +text: .text%__1cUParallelScavengeHeapYpermanent_object_iterate6MpnNObjectClosure__v_; +text: .text%__1cKcmpOpFOperNgreater_equal6kM_i_: ad_sparc_clone.o; +text: .text%__1cUParallelScavengeHeapMmax_capacity6kM_I_; +text: .text%__1cUParallelScavengeHeapPpost_initialize6M_v_; +text: .text%__1cUParallelScavengeHeapKinitialize6M_i_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: parGCAllocBuffer.o; +text: .text%__1cZInterpreterMacroAssemblerbFset_method_data_pointer_for_bcp6M_v_; +text: .text%__SLIP.DELETER__C: ostream.o; +text: .text%__1cMostream_exit6F_v_; +text: .text%__1cQostream_init_log6F_v_; +text: .text%__1cMostream_init6F_v_; +text: .text%__1cCosXnon_memory_address_word6F_pc_; +text: .text%__1cCosGinit_26F_i_; +text: .text%__1cCosEinit6F_v_; +text: .text%__1cCosHSolarisUsynchronization_init6F_v_; +text: .text%__1cVjni_GetLongField_addr6F_pC_; +text: .text%__1cNIdealLoopTreeQsplit_outer_loop6MpnOPhaseIdealLoop__v_; +text: .text%__1cRLowMemoryDetectorKinitialize6F_v_; +text: .text%__1cRLowMemoryDetectorbGlow_memory_detector_thread_entry6FpnKJavaThread_pnGThread__v_; +text: .text%__1cNReservedSpaceUpage_align_size_down6FI_I_; +text: .text%__1cNReservedSpaceYallocation_align_size_up6FI_I_; +text: .text%__1cTloadL_unalignedNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: machnode.o; +text: .text%__1cPmanagement_init6F_v_; +text: .text%__1cOvmStructs_init6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: vmStructs.o; +text: .text%__1cJvmSymbolsKinitialize6FpnGThread__v_; +text: .text%__1cKManagementKinitialize6FpnGThread__v_; +text: .text%__1cKManagementWrecord_vm_startup_time6Fxx_v_; +text: .text%__1cIVMThreadGcreate6F_v_; +text: .text%__1cIVMThreadDrun6M_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: management.o; +text: .text%__1cLJvmtiExportNpost_vm_start6F_v_; +text: .text%__1cLJvmtiExportTpost_vm_initialized6F_v_; +text: .text%__1cLJvmtiExportNpost_vm_death6F_v_; +text: .text%__1cLJvmtiExportbMtransition_pending_onload_raw_monitors6F_v_; +text: .text%__1cUJvmtiPendingMonitorsXtransition_raw_monitors6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: jvmtiImpl.o; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: jvmtiTagMap.o; +text: .text%__1cKklassKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cKklassKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: klassKlass.o; +text: .text%__1cVLoaderConstraintTable2t6Mi_v_; +text: .text%__1cQregL_to_stkLNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cHRetDataPpost_initialize6MpnOBytecodeStream_pnRmethodDataOopDesc__v_; +text: .text%__1cTAbstract_VM_VersionKvm_release6F_pkc_; +text: .text%__1cTAbstract_VM_VersionXinternal_vm_info_string6F_pkc_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: vm_version.o; +text: .text%__1cPVM_Version_init6F_v_; +text: .text%__1cKVM_VersionKinitialize6F_v_; +text: .text%__1cHRetDataJfixup_ret6MinQmethodDataHandle__pC_; +text: .text%__1cLmethodKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cLmethodKlassOset_alloc_size6MI_v_: methodKlass.o; +text: .text%__1cQvtableStubs_init6F_v_; +text: .text%__1cKi0RegPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cKg1RegPOperKin_RegMask6kMi_pknHRegMask__; +text: .text%__1cFVTuneEexit6F_v_; +text: .text%__1cLmethodKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: methodKlass.o; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: methodLiveness.o; +text: .text%__1cMMutableSpaceOobject_iterate6MpnNObjectClosure__v_; +text: .text%__1cKvtune_init6F_v_; +text: .text%__1cKmutex_init6F_v_; +text: .text%__1cQaccessFlags_init6F_v_; +text: .text%__1cOMacroAssemblerMcall_VM_leaf6MpnMRegisterImpl_pC222_v_; +text: .text%__1cTAbstract_VM_VersionJvm_vendor6F_pkc_; +text: .text%__1cOmarksweep_init6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: markSweep.o; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: matcher.o; +text: .text%__1cNMemoryManagerbDget_code_cache_memory_manager6F_p0_; +text: .text%__1cNMemoryManagerbDget_psScavenge_memory_manager6F_pnPGCMemoryManager__; +text: .text%__1cNMemoryManagerbEget_psMarkSweep_memory_manager6F_pnPGCMemoryManager__; +text: .text%__1cHVM_ExitEdoit6M_v_; +text: .text%__1cNMemoryServiceRset_universe_heap6FpnNCollectedHeap__v_; +text: .text%__1cNMemoryServiceZadd_code_heap_memory_pool6FpnICodeHeap__v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: memoryService.o; +text: .text%__1cPmethodDataKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cPmethodDataKlassOset_alloc_size6MI_v_: methodDataKlass.o; +text: .text%__1cPmethodDataKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: methodDataKlass.o; +text: .text%__1cTAbstract_VM_VersionHvm_name6F_pkc_; +text: .text%__1cLstoreF0NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%JNI_CreateJavaVM; +text: .text%__1cQJNI_FastGetFieldbFgenerate_fast_get_boolean_field6F_pC_; +text: .text%__1cQJNI_FastGetFieldbCgenerate_fast_get_byte_field6F_pC_; +text: .text%__1cTtypeArrayKlassKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cQJNI_FastGetFieldbCgenerate_fast_get_char_field6F_pC_; +text: .text%__1cQJNI_FastGetFieldbDgenerate_fast_get_short_field6F_pC_; +text: .text%__1cQJNI_FastGetFieldbBgenerate_fast_get_int_field6F_pC_; +text: .text%__1cQJNI_FastGetFieldbCgenerate_fast_get_long_field6F_pC_; +text: .text%__1cTtypeArrayKlassKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: typeArrayKlassKlass.o; +text: .text%__1cIUniversePcheck_alignment6FIIpkc_v_; +text: .text%__1cIUniverseHgenesis6FpnGThread__v_; +text: .text%__1cVquicken_jni_functions6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: oopMap.o; +text: .text%__1cYjava_lang_reflect_MethodNset_signature6FpnHoopDesc_2_v_; +text: .text%__1cbDjava_lang_reflect_ConstructorPcompute_offsets6F_v_; +text: .text%__1cXjava_lang_reflect_FieldPcompute_offsets6F_v_; +text: .text%__1cXjava_lang_reflect_FieldNset_signature6FpnHoopDesc_2_v_; +text: .text%__1cQdivD_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cLJavaClassesbAcompute_hard_coded_offsets6F_v_; +text: .text%__1cQjavaClasses_init6F_v_; +text: .text%jni_ToReflectedMethod: jni.o; +text: .text%__1cQsubD_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cYjni_GetBooleanField_addr6F_pC_; +text: .text%__1cVjni_GetByteField_addr6F_pC_; +text: .text%__1cQaddF_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cVjni_GetCharField_addr6F_pC_; +text: .text%__1cWjni_GetShortField_addr6F_pC_; +text: .text%__1cUjni_GetIntField_addr6F_pC_; +text: .text%__1cOtypeArrayKlassKinitialize6MpnGThread__v_; +text: .text%__1cWjni_GetFloatField_addr6F_pC_; +text: .text%__1cRsarL_reg_imm6NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cXjni_GetDoubleField_addr6F_pC_; +text: .text%__1cQshlI_reg_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cIUniverseNfixup_mirrors6FpnGThread__v_; +text: .text%JVM_InitializeSocketLibrary; +text: .text%JVM_RegisterUnsafeMethods; +text: .text%__1cOcmovLI_regNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cOcmovLI_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cOcmovDF_regNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%JVM_Socket; +text: .text%__1cbEinitialize_converter_functions6F_v_; +text: .text%JVM_SupportsCX8; +text: .text%__1cOcmovIF_immNodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cUJvmtiEventControllerIvm_start6F_v_; +text: .text%__1cUJvmtiEventControllerHvm_init6F_v_; +text: .text%__1cUJvmtiEventControllerIvm_death6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: jvmtiEventController.o; +text: .text%__1cKstfSSFNodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cLJvmtiExportRenter_start_phase6F_v_; +text: .text%__1cLJvmtiExportQenter_live_phase6F_v_; +text: .text%__1cSmulL_reg_imm13NodeEemit6kMrnKCodeBuffer_pnNPhaseRegAlloc__v_; +text: .text%__1cQJNI_FastGetFieldbDgenerate_fast_get_float_field6F_pC_; +text: .text%__1cSmulI_reg_imm13NodeEsize6kMpnNPhaseRegAlloc__I_; +text: .text%__1cQJNI_FastGetFieldbEgenerate_fast_get_double_field6F_pC_; +text: .text%__1cNuniverse_init6F_i_; +text: .text%__1cOuniverse2_init6F_v_; +text: .text%__1cQjni_handles_init6F_v_; +text: .text%__1cSobjArrayKlassKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: objArrayKlassKlass.o; +text: .text%Unsafe_SetNativeLong; +text: .text%JVM_InitProperties; +text: .text%JVM_Halt; +text: .text%Unsafe_FreeMemory; +text: .text%Unsafe_PageSize; +text: .text%JVM_MaxMemory; +text: .text%__1cSobjArrayKlassKlassbEallocate_system_objArray_klass6MpnGThread__pnMklassOopDesc__; +text: .text%__1cSobjArrayKlassKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%JVM_GetClassDeclaredMethods; +text: .text%__1cPPerfDataManagerHsampled6F_pnMPerfDataList__; +text: .text%__1cQSystemDictionaryKclasses_do6FpFpnMklassOopDesc__v_v_; +text: .text%__1cQSystemDictionaryKinitialize6FpnGThread__v_; +text: .text%__1cQSystemDictionarybCinitialize_preloaded_classes6FpnGThread__v_; +text: .text%__1cPciObjectFactoryTinit_shared_objects6M_v_; +text: .text%__1cPClassFileParserbFjava_lang_ref_Reference_fix_pre6MpnPtypeArrayHandle_nSconstantPoolHandle_pnUFieldAllocationCount_pnGThread__v_; +text: .text%__1cLClassLoaderbBsetup_bootstrap_search_path6F_v_; +text: .text%__1cLClassLoaderQload_zip_library6F_v_; +text: .text%__1cLClassLoaderZcreate_package_info_table6F_v_; +text: .text%__1cLClassLoaderKinitialize6F_v_; +text: .text%__1cLClassLoaderVcompute_Object_vtable6F_i_; +text: .text%__1cMPeriodicTask2T5B6M_v_; +text: .text%__1cQclassLoader_init6F_v_; +text: .text%__1cMPeriodicTaskJdisenroll6M_v_; +text: .text%__1cOBasicHashtable2t6Mii_v_: classLoader.o; +text: .text%__1cTClassLoadingServiceEinit6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: regmask.o; +text: .text%__1cUciObjArrayKlassKlassEmake6F_p0_; +text: .text%__1cVRegistersForDebuggingRrestore_registers6FpnOMacroAssembler_pnMRegisterImpl__v_: assembler_sparc.o; +text: .text%__1cVRegistersForDebuggingOsave_registers6FpnOMacroAssembler__v_: assembler_sparc.o; +text: .text%__1cJBytecodesKinitialize6F_v_; +text: .text%__1cQSystemDictionarybAcompute_java_system_loader6FpnGThread__v_; +text: .text%__1cObytecodes_init6F_v_; +text: .text%__1cLOptoRuntimeIgenerate6FpnFciEnv__v_; +text: .text%__1cJBytecodesNpd_initialize6F_v_; +text: .text%__1cHCompileRpd_compiler2_init6F_v_; +text: .text%__1cKC2CompilerKinitialize6M_v_; +text: .text%__1cRCardTableModRefBS2t6MnJMemRegion_i_v_; +text: .text%__1cRCardTableModRefBSbBct_max_alignment_constraint6F_I_; +text: .text%__1cMciArrayKlass2t6MpnIciSymbol_ipnHciKlass__v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: relocInfo.o; +text: .text%__1cMciKlassKlassEmake6F_p0_; +text: .text%__1cIciMethodMvtable_index6M_i_; +text: .text%__1cPciObjArrayKlass2t6MpnIciSymbol_pnHciKlass_i_v_; +text: .text%__1cJLoadFNodeMstore_Opcode6kM_i_: classes.o; +text: .text%__1cNTemplateTableGsipush6F_v_; +text: .text%__1cQUncommonTrapBlobGcreate6FpnKCodeBuffer_pnJOopMapSet_i_p0_; +text: .text%__1cNTemplateTableGldc2_w6F_v_; +text: .text%__1cNExceptionBlobGcreate6FpnKCodeBuffer_pnJOopMapSet_i_p0_; +text: .text%__1cNTemplateTableFiload6F_v_; +text: .text%__1cNTemplateTableLfast_iload26F_v_; +text: .text%__1cNTemplateTableKfast_iload6F_v_; +text: .text%__1cNTemplateTableFlload6F_v_; +text: .text%__1cNTemplateTableFfload6F_v_; +text: .text%__1cNTemplateTableFdload6F_v_; +text: .text%__1cNTemplateTableFaload6F_v_; +text: .text%__1cNTemplateTableKwide_iload6F_v_; +text: .text%__1cNTemplateTableKwide_lload6F_v_; +text: .text%__1cNTemplateTableKwide_fload6F_v_; +text: .text%__1cNTemplateTableKwide_dload6F_v_; +text: .text%__1cNTemplateTableKwide_aload6F_v_; +text: .text%__1cNTemplateTableGiaload6F_v_; +text: .text%__1cNTemplateTableGlaload6F_v_; +text: .text%__1cNTemplateTableGfaload6F_v_; +text: .text%__1cNTemplateTableGdaload6F_v_; +text: .text%__1cNTemplateTableGbipush6F_v_; +text: .text%__1cLMoveF2INodeJideal_reg6kM_I_: classes.o; +text: .text%__1cLMoveL2DNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cNTemplateTableHcall_VM6FpnMRegisterImpl_pC222_v_; +text: .text%__1cHOrLNodeGadd_id6kM_pknEType__: classes.o; +text: .text%__1cHOrLNodeJideal_reg6kM_I_: classes.o; +text: .text%__1cNTemplateTableF_goto6F_v_; +text: .text%__1cNTemplateTableGgoto_w6F_v_; +text: .text%__1cNTemplateTableFjsr_w6F_v_; +text: .text%__1cNTemplateTableDjsr6F_v_; +text: .text%__1cXreferenceProcessor_init6F_v_; +text: .text%__1cICodeBlobMset_oop_maps6MpnJOopMapSet__v_; +text: .text%__1cStemplateTable_init6F_v_; +text: .text%__1cNTemplateTableNpd_initialize6F_v_; +text: .text%__1cNTemplateTableDnop6F_v_; +text: .text%__1cNTemplateTableSshouldnotreachhere6F_v_; +text: .text%__1cNTemplateTableLaconst_null6F_v_; +text: .text%__1cKPSYoungGenbCreset_survivors_after_shrink6M_v_; +text: .text%__1cKPSYoungGenQlimit_gen_shrink6MI_I_; +text: .text%__1cKPSYoungGenRavailable_to_live6M_I_; +text: .text%__1cSDeoptimizationBlobGcreate6FpnKCodeBuffer_pnJOopMapSet_iiii_p0_; +text: .text%__1cLOptoRuntimeUmultianewarray2_Type6F_pknITypeFunc__; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: ad_sparc_pipeline.o; +text: .text%__1cUAdjoiningGenerations2t6MnNReservedSpace_IIIIIII_v_; +text: .text%__1cWAdjoiningVirtualSpaces2t6MnNReservedSpace_III_v_; +text: .text%__1cOchunkpool_init6F_v_; +text: .text%__1cFChunkbDstart_chunk_pool_cleaner_task6F_v_; +text: .text%__1cJArgumentsWinit_system_properties6F_v_; +text: .text%__1cMSysClassPathPexpand_endorsed6M_v_; +text: .text%__1cMSysClassPathQadd_jars_to_path6Fpcpkc_1_; +text: .text%__1cJArgumentsTset_parnew_gc_flags6F_v_; +text: .text%__1cJArgumentsbBset_cms_and_parnew_gc_flags6F_v_; +text: .text%__1cJArgumentsUset_ergonomics_flags6F_v_; +text: .text%__1cJArgumentsSparse_vm_init_args6FpknOJavaVMInitArgs__i_; +text: .text%__1cLStatSamplerGengage6F_v_; +text: .text%__1cNStubGeneratorbNgenerate_flush_callers_register_windows6M_pC_: stubGenerator_sparc.o; +text: .text%__1cSstubRoutines_init16F_v_; +text: .text%__1cSstubRoutines_init26F_v_; +text: .text%__1cNStubGeneratorbIgenerate_handler_for_unsafe_access6M_pC_: stubGenerator_sparc.o; +text: .text%__1cNStubGeneratorbAgenerate_forward_exception6M_pC_: stubGenerator_sparc.o; +text: .text%__1cNStubGeneratorSgenerate_call_stub6MrpC_1_: stubGenerator_sparc.o; +text: .text%__1cNStubGeneratorYgenerate_catch_exception6M_pC_: stubGenerator_sparc.o; +text: .text%__1cNStubGeneratorSgenerate_test_stop6M_pC_: stubGenerator_sparc.o; +text: .text%__1cNStubGeneratorbEgenerate_partial_subtype_check6M_pC_: stubGenerator_sparc.o; +text: .text%__1cISubFNodeDsub6kMpknEType_3_3_; +text: .text%__1cRStubCodeGeneratorLstub_prolog6MpnMStubCodeDesc__v_; +text: .text%__1cLStatSamplerbMcreate_system_property_instrumentation6FpnGThread__v_; +text: .text%__1cLStatSamplerHdestroy6F_v_; +text: .text%__1cLStatSamplerJdisengage6F_v_; +text: .text%__1cNRegisterSaverYrestore_result_registers6FpnOMacroAssembler__v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: runtimeService.o; +text: .text%__1cORuntimeServiceYrecord_application_start6F_v_; +text: .text%__1cOMacroAssemblerNset_vm_result6MpnMRegisterImpl__v_; +text: .text%__1cORuntimeServiceEinit6F_v_; +text: .text%__1cOMacroAssemblerVverify_oop_subroutine6M_v_; +text: .text%__1cOMacroAssemblerPstop_subroutine6M_v_; +text: .text%__1cOMacroAssemblerElcmp6MpnMRegisterImpl_2222_v_; +text: .text%__1cOMacroAssemblerElneg6MpnMRegisterImpl_2_v_; +text: .text%__1cOMacroAssemblerElshl6MpnMRegisterImpl_22222_v_; +text: .text%__1cOMacroAssemblerElshr6MpnMRegisterImpl_22222_v_; +text: .text%__1cOMacroAssemblerFlushr6MpnMRegisterImpl_22222_v_; +text: .text%__1cLOptoRuntimeUmultianewarray5_Type6F_pknITypeFunc__; +text: .text%__1cLOptoRuntimeUmultianewarray4_Type6F_pknITypeFunc__; +text: .text%__1cLOptoRuntimeUmultianewarray3_Type6F_pknITypeFunc__; +text: .text%__1cLsymbolKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: symbolKlass.o; +text: .text%__1cJArgumentsFparse6FpknOJavaVMInitArgs__i_; +text: .text%__1cJArgumentsWPropertyList_get_value6FpnOSystemProperty_pkc_4_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: sharedHeap.o; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: arguments.o; +text: .text%__1cParrayKlassKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cKklassKlassOset_alloc_size6MI_v_: arrayKlassKlass.o; +text: .text%__1cLsymbolKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cParrayKlassKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: arrayKlassKlass.o; +text: .text%__1cOMacroAssemblerRcall_VM_leaf_base6MpnMRegisterImpl_pCi_v_; +text: .text%__1cNSharedRuntimeTgenerate_deopt_blob6F_v_; +text: .text%__1cLsymbolKlassOset_alloc_size6MI_v_: symbolKlass.o; +text: .text%__1cNTemplateTableGaaload6F_v_; +text: .text%__1cQconstMethodKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cQconstMethodKlassOset_alloc_size6MI_v_: constMethodKlass.o; +text: .text%__1cQconstMethodKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: constMethodKlass.o; +text: .text%__1cGThreadMset_priority6Fp0nOThreadPriority__v_; +text: .text%__1cRconstantPoolKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cRconstantPoolKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: constantPoolKlass.o; +text: .text%__1cQPlaceholderTable2t6Mi_v_; +text: .text%__1cbBcreate_initial_thread_group6FpnGThread__nGHandle__: thread.o; +text: .text%__1cVcreate_initial_thread6FnGHandle_pnKJavaThread_pnGThread__pnHoopDesc__: thread.o; +text: .text%__1cbAcall_initializeSystemClass6FpnGThread__v_: thread.o; +text: .text%__1cWreset_vm_info_property6FpnGThread__v_: thread.o; +text: .text%__1cbAPSGCAdaptivePolicyCounters2t6MpkciipnUPSAdaptiveSizePolicy__v_; +text: .text%__1cNTemplateTableRfast_invokevfinal6Fi_v_; +text: .text%__1cVcompiledICHolderKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: compiledICHolderKlass.o; +text: .text%__1cNTemplateTableNinvokespecial6Fi_v_; +text: .text%__1cNTemplateTableMinvokestatic6Fi_v_; +text: .text%__1cNTemplateTablebDinvokeinterface_object_method6FpnMRegisterImpl_222_v_; +text: .text%__1cNTemplateTablePinvokeinterface6Fi_v_; +text: .text%__1cNTemplateTableE_new6F_v_; +text: .text%__1cNTemplateTableInewarray6F_v_; +text: .text%__1cNTemplateTableJanewarray6F_v_; +text: .text%__1cNTemplateTableLarraylength6F_v_; +text: .text%__1cNTemplateTableJcheckcast6F_v_; +text: .text%__1cNTemplateTableKinstanceof6F_v_; +text: .text%__1cNTemplateTableL_breakpoint6F_v_; +text: .text%__1cNTemplateTableGathrow6F_v_; +text: .text%__1cNTemplateTableMmonitorenter6F_v_; +text: .text%__1cNTemplateTableLmonitorexit6F_v_; +text: .text%__1cNTemplateTableEwide6F_v_; +text: .text%__1cNTemplateTableOmultianewarray6F_v_; +text: .text%__1cTcompilerOracle_init6F_v_; +text: .text%__1cWconstantPoolCacheKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cPPerfDataManagerTcreate_long_counter6FnJCounterNS_pkcnIPerfDataFUnits_pnUPerfLongSampleHelper_pnGThread__pnPPerfLongCounter__; +text: .text%__1cZCompiledArgumentOopFinderRhandle_oop_offset6M_v_: frame.o; +text: .text%__1cQGCPolicyCounters2t6Mpkcii_v_; +text: .text%__1cHGCStats2t6M_v_; +text: .text%__1cNGCTaskManager2t6MI_v_; +text: .text%__1cNGCTaskManagerKinitialize6M_v_; +text: .text%__1cNGCTaskManagerKthreads_do6MpnNThreadClosure__v_; +text: .text%__1cPPerfDataManagerHdestroy6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: genCollectedHeap.o; +text: .text%__1cJGenRemSetYmax_alignment_constraint6Fn0AEName__I_; +text: .text%__1cWResolveOopMapConflictsUdo_potential_rewrite6MpnGThread__nMmethodHandle__; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: generateOopMap.o; +text: .text%__1cOThreadCriticalKinitialize6F_v_; +text: .text%__1cSThreadLocalStoragebCgenerate_code_for_get_thread6F_v_; +text: .text%__1cICodeHeap2t6M_v_; +text: .text%__1cDhpiKinitialize6F_i_; +text: .text%__1cMPerfDataList2T6M_v_; +text: .text%__1cNWatcherThreadDrun6M_v_; +text: .text%__1cNWatcherThreadEstop6F_v_; +text: .text%__1cWconstantPoolCacheKlassSallocate_permanent6kMrnLKlassHandle_ipnGThread__pv_: cpCacheKlass.o; +text: .text%__1cFStateO_sub_Op_CMoveD6MpknENode__v_; +text: .text%__1cFStateP_sub_Op_MoveF2I6MpknENode__v_; +text: .text%__1cKDictionary2t6Mi_v_; +text: .text%__1cKDictionaryKclasses_do6MpFpnMklassOopDesc__v_v_; +text: .text%__1cNeventlog_init6F_v_; +text: .text%__1cScheck_ThreadShadow6F_v_; +text: .text%__1cOtailjmpIndNodeLout_RegMask6kM_rknHRegMask__; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: fprofiler.o; +text: .text%__1cFframeVinterpreter_frame_mdp6kM_pC_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: phase.o; +text: .text%__1cKPerfMemoryUdelete_memory_region6F_v_; +text: .text%__1cKPerfMemoryUcreate_memory_region6FI_v_; +text: .text%__1cbBcleanup_sharedmem_resources6Fpkc_v_: perfMemory_solaris.o; +text: .text%__1cPperfMemory_exit6F_v_; +text: .text%__1cPperfMemory_init6F_v_; +text: .text%__1cNTemplateTableNinvokevirtual6Fi_v_; +text: .text%__1cNTemplateTableHfastore6F_v_; +text: .text%__1cNTemplateTableHdastore6F_v_; +text: .text%__1cNTemplateTableHaastore6F_v_; +text: .text%__1cNTemplateTableHbastore6F_v_; +text: .text%__1cNTemplateTableHsastore6F_v_; +text: .text%__1cOcodeCache_init6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: codeCache.o; +text: .text%__1cNTemplateTableDpop6F_v_; +text: .text%__1cNTemplateTableEpop26F_v_; +text: .text%__1cNTemplateTableDdup6F_v_; +text: .text%__1cNTemplateTableGdup_x16F_v_; +text: .text%__1cNTemplateTableGdup_x26F_v_; +text: .text%__1cNTemplateTableEdup26F_v_; +text: .text%__1cNTemplateTableHdup2_x16F_v_; +text: .text%__1cNTemplateTableHdup2_x26F_v_; +text: .text%__1cNTemplateTableEswap6F_v_; +text: .text%__1cNCollectedHeap2t6M_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: psScavenge.o; +text: .text%__1cNTemplateTableEirem6F_v_; +text: .text%__1cNTemplateTableElmul6F_v_; +text: .text%__1cNTemplateTableHlastore6F_v_; +text: .text%__1cNTemplateTableGbaload6F_v_; +text: .text%__1cNTemplateTableGcaload6F_v_; +text: .text%__1cNTemplateTableMfast_icaload6F_v_; +text: .text%__1cNTemplateTableGsaload6F_v_; +text: .text%__1cKPSYoungGenPinitialize_work6M_v_; +text: .text%__1cKPSYoungGenKinitialize6MnNReservedSpace_I_v_; +text: .text%__1cKPSYoungGenYinitialize_virtual_space6MnNReservedSpace_I_v_; +text: .text%__1cKPSYoungGen2t6MIII_v_; +text: .text%__1cNTemplateTableHaload_06F_v_; +text: .text%__1cNTemplateTableGistore6F_v_; +text: .text%__1cNTemplateTableGlstore6F_v_; +text: .text%__1cNTemplateTableGfstore6F_v_; +text: .text%__1cNTemplateTableGdstore6F_v_; +text: .text%__1cNTemplateTableGastore6F_v_; +text: .text%__1cNTemplateTableLwide_istore6F_v_; +text: .text%__1cNTemplateTableLwide_lstore6F_v_; +text: .text%__1cNTemplateTableLwide_fstore6F_v_; +text: .text%__1cNTemplateTableLwide_dstore6F_v_; +text: .text%__1cNTemplateTableLwide_astore6F_v_; +text: .text%__1cNTemplateTableHiastore6F_v_; +text: .text%__1cNTemplateTableEldiv6F_v_; +text: .text%__1cNTemplateTableLtableswitch6F_v_; +text: .text%__1cNTemplateTableMlookupswitch6F_v_; +text: .text%__1cNTemplateTableRfast_linearswitch6F_v_; +text: .text%__1cNTemplateTableRfast_binaryswitch6F_v_; +text: .text%__1cNCompileBrokerVinit_compiler_threads6Fi_v_; +text: .text%__1cJPSPermGen2t6MnNReservedSpace_IIIIpkci_v_; +text: .text%__1cNCompileBrokerQset_should_block6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: compileBroker.o; +text: .text%__1cNTemplateTableIgetfield6Fi_v_; +text: .text%__1cNTemplateTableJgetstatic6Fi_v_; +text: .text%__1cIPSOldGenKinitialize6MnNReservedSpace_Ipkci_v_; +text: .text%__1cIPSOldGen2t6MIIIpkci_v_; +text: .text%__1cIPSOldGen2t6MnNReservedSpace_IIIIpkci_v_; +text: .text%__1cVcompiledICHolderKlassMcreate_klass6FpnGThread__pnMklassOopDesc__; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: psMarkSweep.o; +text: .text%__1cNTemplateTableIputfield6Fi_v_; +text: .text%__1cNTemplateTableJputstatic6Fi_v_; +text: .text%__1cVcompiledICHolderKlassOset_alloc_size6MI_v_: compiledICHolderKlass.o; +text: .text%__1cLPSMarkSweepKinitialize6F_v_; +text: .text%__1cNTemplateTableIwide_ret6F_v_; +text: .text%__1cNTemplateTableElrem6F_v_; +text: .text%__1cNTemplateTableElshl6F_v_; +text: .text%__1cNTemplateTableElshr6F_v_; +text: .text%__1cNTemplateTableFlushr6F_v_; +text: .text%__1cbCTwoGenerationCollectorPolicyQinitialize_flags6M_v_; +text: .text%__1cbCTwoGenerationCollectorPolicyUinitialize_size_info6M_v_; +text: .text%__1cNTemplateTableEineg6F_v_; +text: .text%__1cNTemplateTableElneg6F_v_; +text: .text%__1cNTemplateTableEfneg6F_v_; +text: .text%__1cNTemplateTableEdneg6F_v_; +text: .text%__1cNTemplateTableEiinc6F_v_; +text: .text%__1cNTemplateTableJwide_iinc6F_v_; +text: .text%__1cKPSScavengeKinitialize6F_v_; +text: .text%__1cNTemplateTableElcmp6F_v_; +text: .text%__1cWcompilationPolicy_init6F_v_; +text: .text%__1cRCompilationPolicyUcompleted_vm_startup6F_v_; +text: .text%__1cU__STATIC_CONSTRUCTOR6F_v_: compilationPolicy.o; +text: .text%__1cSPSPromotionManagerKinitialize6F_v_; +text: .text%__1cNTemplateTableDret6F_v_; diff --git a/hotspot/make/solaris/makefiles/sa.make b/hotspot/make/solaris/makefiles/sa.make index 8d4313b6e3b..b81fa3e2d4b 100644 --- a/hotspot/make/solaris/makefiles/sa.make +++ b/hotspot/make/solaris/makefiles/sa.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,9 @@ MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules AGENT_FILES1 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES1)) AGENT_FILES2 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES2)) +AGENT_FILES1_LIST := $(GENERATED)/agent1.classes.list +AGENT_FILES2_LIST := $(GENERATED)/agent2.classes.list + SA_CLASSDIR = $(GENERATED)/saclasses SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION)" @@ -70,8 +73,23 @@ $(GENERATED)/sa-jdi.jar: $(AGENT_FILES1) $(AGENT_FILES2) $(QUIETLY) if [ ! -d $(SA_CLASSDIR) ] ; then \ mkdir -p $(SA_CLASSDIR); \ fi - $(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES1) - $(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES2) + +# Note: When indented, make tries to execute the '$(shell' comment. +# In some environments, cmd processors have limited line length. +# To prevent the javac invocation in the next block from using +# a very long cmd line, we use javac's @file-list option. We +# generate the file lists using make's built-in 'foreach' control +# flow which also avoids cmd processor line length issues. Since +# the 'foreach' is done as part of make's macro expansion phase, +# the initialization of the lists is also done in the same phase +# using '$(shell rm ...' instead of using the more traditional +# 'rm ...' rule. + $(shell rm -rf $(AGENT_FILES1_LIST) $(AGENT_FILES2_LIST)) + $(foreach file,$(AGENT_FILES1),$(shell echo $(file) >> $(AGENT_FILES1_LIST))) + $(foreach file,$(AGENT_FILES2),$(shell echo $(file) >> $(AGENT_FILES2_LIST))) + + $(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST) + $(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST) $(QUIETLY) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) @@ -88,3 +106,4 @@ $(GENERATED)/sa-jdi.jar: $(AGENT_FILES1) $(AGENT_FILES2) clean: rm -rf $(SA_CLASSDIR) rm -rf $(GENERATED)/sa-jdi.jar + rm -rf $(AGENT_FILES1_LIST) $(AGENT_FILES2_LIST) diff --git a/hotspot/make/templates/bsd-header b/hotspot/make/templates/bsd-header index 71d0a8bb42b..95ed87bae36 100644 --- a/hotspot/make/templates/bsd-header +++ b/hotspot/make/templates/bsd-header @@ -1,4 +1,4 @@ -Copyright %YEARS% Oracle and/or its affiliates. All rights reserved. +Copyright (c) %YEARS%, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions diff --git a/hotspot/make/templates/gpl-cp-header b/hotspot/make/templates/gpl-cp-header index 8f9d5026647..f5b3943c4c9 100644 --- a/hotspot/make/templates/gpl-cp-header +++ b/hotspot/make/templates/gpl-cp-header @@ -1,4 +1,4 @@ -Copyright %YEARS% Oracle and/or its affiliates. All rights reserved. +Copyright (c) %YEARS%, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/make/templates/gpl-header b/hotspot/make/templates/gpl-header index b979ccc8859..9eadb48b613 100644 --- a/hotspot/make/templates/gpl-header +++ b/hotspot/make/templates/gpl-header @@ -1,4 +1,4 @@ -Copyright %YEARS% Oracle and/or its affiliates. All rights reserved. +Copyright (c) %YEARS%, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/make/windows/build.make b/hotspot/make/windows/build.make index fdce33f4a07..1c502ca1eb3 100644 --- a/hotspot/make/windows/build.make +++ b/hotspot/make/windows/build.make @@ -1,5 +1,5 @@ # -# Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # # Note: this makefile is invoked both from build.bat and from the J2SE @@ -72,13 +72,11 @@ BUILDARCH=ia64 !endif !endif -!if "$(BUILDARCH)" != "amd64" !if "$(BUILDARCH)" != "ia64" !ifndef CC_INTERP FORCE_TIERED=1 !endif !endif -!endif !if "$(BUILDARCH)" == "amd64" Platform_arch=x86 @@ -135,7 +133,7 @@ VARIANT_TEXT=Kernel # We can have update versions like "01a", but Windows requires # we use only integers in the file version field. So: # JDK_UPDATE_VER = JDK_UPDATE_VERSION * 10 + EXCEPTION_VERSION -# +# JDK_UPDATE_VER=0 JDK_BUILD_NUMBER=0 @@ -148,7 +146,7 @@ HS_FILEDESC=$(HOTSPOT_VM_DISTRO) $(ARCH_TEXT) $(VARIANT_TEXT) VM # 1.6.0_01a-b02 will be 6.0.11.2 # # JDK_* variables are defined in make/hotspot_version or on command line -# +# JDK_VER=$(JDK_MINOR_VER),$(JDK_MICRO_VER),$(JDK_UPDATE_VER),$(JDK_BUILD_NUMBER) JDK_DOTVER=$(JDK_MINOR_VER).$(JDK_MICRO_VER).$(JDK_UPDATE_VER).$(JDK_BUILD_NUMBER) !if "$(JRE_RELEASE_VERSION)" == "" @@ -162,7 +160,7 @@ JDK_MKTG_VERSION=$(JDK_MINOR_VER).$(JDK_MICRO_VER) # Hotspot Express VM FileVersion: # 10.0-b will have DLL version 10.0.0.yz (need 4 numbers). -# +# # HS_* variables are defined in make/hotspot_version # HS_VER=$(HS_MAJOR_VER),$(HS_MINOR_VER),0,$(HS_BUILD_NUMBER) @@ -182,7 +180,7 @@ HS_BUILD_VER=$(HOTSPOT_RELEASE_VERSION)-$(HOTSPOT_BUILD_VERSION) # We don't support SA on ia64, and we can't -# build it if we are using a version of Vis Studio +# build it if we are using a version of Vis Studio # older than .Net 2003. # SA_INCLUDE and SA_LIB are hold-overs from a previous # implementation in which we could build SA using diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp index 1239483966c..e84e92a41c7 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp @@ -4192,7 +4192,7 @@ static void check_index(int ind) { static void generate_satb_log_enqueue(bool with_frame) { BufferBlob* bb = BufferBlob::create("enqueue_with_frame", EnqueueCodeSize); - CodeBuffer buf(bb->instructions_begin(), bb->instructions_size()); + CodeBuffer buf(bb); MacroAssembler masm(&buf); address start = masm.pc(); Register pre_val; @@ -4421,7 +4421,7 @@ static u_char* dirty_card_log_enqueue_end = 0; // This gets to assume that o0 contains the object address. static void generate_dirty_card_log_enqueue(jbyte* byte_map_base) { BufferBlob* bb = BufferBlob::create("dirty_card_enqueue", EnqueueCodeSize*2); - CodeBuffer buf(bb->instructions_begin(), bb->instructions_size()); + CodeBuffer buf(bb); MacroAssembler masm(&buf); address start = masm.pc(); diff --git a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp index efc250edb4b..709259740f5 100644 --- a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp @@ -57,13 +57,12 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { #endif } -#ifdef TIERED void CounterOverflowStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); __ set(_bci, G4); __ call(Runtime1::entry_for(Runtime1::counter_overflow_id), relocInfo::runtime_call_type); - __ delayed()->nop(); + __ delayed()->mov_or_nop(_method->as_register(), G5); ce->add_call_info_here(_info); ce->verify_oop_map(_info); @@ -71,7 +70,6 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) { __ delayed()->nop(); } -#endif // TIERED void DivByZeroStub::emit_code(LIR_Assembler* ce) { if (_offset != -1) { diff --git a/hotspot/src/cpu/sparc/vm/c1_FrameMap_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_FrameMap_sparc.cpp index e81b874a403..2bf36306771 100644 --- a/hotspot/src/cpu/sparc/vm/c1_FrameMap_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_FrameMap_sparc.cpp @@ -73,6 +73,7 @@ FloatRegister FrameMap::_fpu_regs [FrameMap::nof_fpu_regs]; // some useful constant RInfo's: LIR_Opr FrameMap::in_long_opr; LIR_Opr FrameMap::out_long_opr; +LIR_Opr FrameMap::g1_long_single_opr; LIR_Opr FrameMap::F0_opr; LIR_Opr FrameMap::F0_double_opr; @@ -238,6 +239,7 @@ void FrameMap::initialize() { in_long_opr = as_long_opr(I0); out_long_opr = as_long_opr(O0); + g1_long_single_opr = as_long_single_opr(G1); G0_opr = as_opr(G0); G1_opr = as_opr(G1); diff --git a/hotspot/src/cpu/sparc/vm/c1_FrameMap_sparc.hpp b/hotspot/src/cpu/sparc/vm/c1_FrameMap_sparc.hpp index 592d30b4103..10dfbceadd6 100644 --- a/hotspot/src/cpu/sparc/vm/c1_FrameMap_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c1_FrameMap_sparc.hpp @@ -103,6 +103,7 @@ static LIR_Opr in_long_opr; static LIR_Opr out_long_opr; + static LIR_Opr g1_long_single_opr; static LIR_Opr F0_opr; static LIR_Opr F0_double_opr; @@ -113,18 +114,25 @@ private: static FloatRegister _fpu_regs [nof_fpu_regs]; + static LIR_Opr as_long_single_opr(Register r) { + return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); + } + static LIR_Opr as_long_pair_opr(Register r) { + return LIR_OprFact::double_cpu(cpu_reg2rnr(r->successor()), cpu_reg2rnr(r)); + } + public: #ifdef _LP64 static LIR_Opr as_long_opr(Register r) { - return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); + return as_long_single_opr(r); } static LIR_Opr as_pointer_opr(Register r) { - return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); + return as_long_single_opr(r); } #else static LIR_Opr as_long_opr(Register r) { - return LIR_OprFact::double_cpu(cpu_reg2rnr(r->successor()), cpu_reg2rnr(r)); + return as_long_pair_opr(r); } static LIR_Opr as_pointer_opr(Register r) { return as_opr(r); diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index 4b489b81dfc..143cd93f17e 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -1625,13 +1625,18 @@ void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type, void LIR_Assembler::return_op(LIR_Opr result) { // the poll may need a register so just pick one that isn't the return register -#ifdef TIERED +#if defined(TIERED) && !defined(_LP64) if (result->type_field() == LIR_OprDesc::long_type) { // Must move the result to G1 // Must leave proper result in O0,O1 and G1 (TIERED only) __ sllx(I0, 32, G1); // Shift bits into high G1 __ srl (I1, 0, I1); // Zero extend O1 (harmless?) __ or3 (I1, G1, G1); // OR 64 bits into G1 +#ifdef ASSERT + // mangle it so any problems will show up + __ set(0xdeadbeef, I0); + __ set(0xdeadbeef, I1); +#endif } #endif // TIERED __ set((intptr_t)os::get_polling_page(), L0); @@ -2424,6 +2429,192 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { } +void LIR_Assembler::type_profile_helper(Register mdo, int mdo_offset_bias, + ciMethodData *md, ciProfileData *data, + Register recv, Register tmp1, Label* update_done) { + uint i; + for (i = 0; i < VirtualCallData::row_limit(); i++) { + Label next_test; + // See if the receiver is receiver[n]. + Address receiver_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - + mdo_offset_bias); + __ ld_ptr(receiver_addr, tmp1); + __ verify_oop(tmp1); + __ cmp(recv, tmp1); + __ brx(Assembler::notEqual, false, Assembler::pt, next_test); + __ delayed()->nop(); + Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - + mdo_offset_bias); + __ ld_ptr(data_addr, tmp1); + __ add(tmp1, DataLayout::counter_increment, tmp1); + __ st_ptr(tmp1, data_addr); + __ ba(false, *update_done); + __ delayed()->nop(); + __ bind(next_test); + } + + // Didn't find receiver; find next empty slot and fill it in + for (i = 0; i < VirtualCallData::row_limit(); i++) { + Label next_test; + Address recv_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - + mdo_offset_bias); + load(recv_addr, tmp1, T_OBJECT); + __ br_notnull(tmp1, false, Assembler::pt, next_test); + __ delayed()->nop(); + __ st_ptr(recv, recv_addr); + __ set(DataLayout::counter_increment, tmp1); + __ st_ptr(tmp1, mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - + mdo_offset_bias); + __ ba(false, *update_done); + __ delayed()->nop(); + __ bind(next_test); + } +} + + +void LIR_Assembler::setup_md_access(ciMethod* method, int bci, + ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias) { + md = method->method_data(); + if (md == NULL) { + bailout("out of memory building methodDataOop"); + return; + } + data = md->bci_to_data(bci); + assert(data != NULL, "need data for checkcast"); + assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); + if (!Assembler::is_simm13(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) { + // The offset is large so bias the mdo by the base of the slot so + // that the ld can use simm13s to reference the slots of the data + mdo_offset_bias = md->byte_offset_of_slot(data, DataLayout::header_offset()); + } +} + +void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) { + // we always need a stub for the failure case. + CodeStub* stub = op->stub(); + Register obj = op->object()->as_register(); + Register k_RInfo = op->tmp1()->as_register(); + Register klass_RInfo = op->tmp2()->as_register(); + Register dst = op->result_opr()->as_register(); + Register Rtmp1 = op->tmp3()->as_register(); + ciKlass* k = op->klass(); + + + if (obj == k_RInfo) { + k_RInfo = klass_RInfo; + klass_RInfo = obj; + } + + ciMethodData* md; + ciProfileData* data; + int mdo_offset_bias = 0; + if (op->should_profile()) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); + + Label not_null; + __ br_notnull(obj, false, Assembler::pn, not_null); + __ delayed()->nop(); + Register mdo = k_RInfo; + Register data_val = Rtmp1; + jobject2reg(md->constant_encoding(), mdo); + if (mdo_offset_bias > 0) { + __ set(mdo_offset_bias, data_val); + __ add(mdo, data_val, mdo); + } + Address flags_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias); + __ ldub(flags_addr, data_val); + __ or3(data_val, BitData::null_seen_byte_constant(), data_val); + __ stb(data_val, flags_addr); + __ ba(false, *obj_is_null); + __ delayed()->nop(); + __ bind(not_null); + } else { + __ br_null(obj, false, Assembler::pn, *obj_is_null); + __ delayed()->nop(); + } + + Label profile_cast_failure, profile_cast_success; + Label *failure_target = op->should_profile() ? &profile_cast_failure : failure; + Label *success_target = op->should_profile() ? &profile_cast_success : success; + + // patching may screw with our temporaries on sparc, + // so let's do it before loading the class + if (k->is_loaded()) { + jobject2reg(k->constant_encoding(), k_RInfo); + } else { + jobject2reg_with_patching(k_RInfo, op->info_for_patch()); + } + assert(obj != k_RInfo, "must be different"); + + // get object class + // not a safepoint as obj null check happens earlier + load(obj, oopDesc::klass_offset_in_bytes(), klass_RInfo, T_OBJECT, NULL); + if (op->fast_check()) { + assert_different_registers(klass_RInfo, k_RInfo); + __ cmp(k_RInfo, klass_RInfo); + __ brx(Assembler::notEqual, false, Assembler::pt, *failure_target); + __ delayed()->nop(); + } else { + bool need_slow_path = true; + if (k->is_loaded()) { + if (k->super_check_offset() != sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()) + need_slow_path = false; + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, noreg, + (need_slow_path ? success_target : NULL), + failure_target, NULL, + RegisterOrConstant(k->super_check_offset())); + } else { + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, success_target, + failure_target, NULL); + } + if (need_slow_path) { + // call out-of-line instance of __ check_klass_subtype_slow_path(...): + assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); + __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); + __ delayed()->nop(); + __ cmp(G3, 0); + __ br(Assembler::equal, false, Assembler::pn, *failure_target); + __ delayed()->nop(); + // Fall through to success case + } + } + + if (op->should_profile()) { + Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1; + assert_different_registers(obj, mdo, recv, tmp1); + __ bind(profile_cast_success); + jobject2reg(md->constant_encoding(), mdo); + if (mdo_offset_bias > 0) { + __ set(mdo_offset_bias, tmp1); + __ add(mdo, tmp1, mdo); + } + load(Address(obj, oopDesc::klass_offset_in_bytes()), recv, T_OBJECT); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, success); + // Jump over the failure case + __ ba(false, *success); + __ delayed()->nop(); + // Cast failure case + __ bind(profile_cast_failure); + jobject2reg(md->constant_encoding(), mdo); + if (mdo_offset_bias > 0) { + __ set(mdo_offset_bias, tmp1); + __ add(mdo, tmp1, mdo); + } + Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias); + __ ld_ptr(data_addr, tmp1); + __ sub(tmp1, DataLayout::counter_increment, tmp1); + __ st_ptr(tmp1, data_addr); + __ ba(false, *failure); + __ delayed()->nop(); + } + __ ba(false, *success); + __ delayed()->nop(); +} + void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { LIR_Code code = op->code(); if (code == lir_store_check) { @@ -2434,193 +2625,106 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { Register Rtmp1 = op->tmp3()->as_register(); __ verify_oop(value); - CodeStub* stub = op->stub(); - Label done; - __ cmp(value, 0); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); + // check if it needs to be profiled + ciMethodData* md; + ciProfileData* data; + int mdo_offset_bias = 0; + if (op->should_profile()) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); + } + Label profile_cast_success, profile_cast_failure, done; + Label *success_target = op->should_profile() ? &profile_cast_success : &done; + Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); + + if (op->should_profile()) { + Label not_null; + __ br_notnull(value, false, Assembler::pn, not_null); + __ delayed()->nop(); + Register mdo = k_RInfo; + Register data_val = Rtmp1; + jobject2reg(md->constant_encoding(), mdo); + if (mdo_offset_bias > 0) { + __ set(mdo_offset_bias, data_val); + __ add(mdo, data_val, mdo); + } + Address flags_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias); + __ ldub(flags_addr, data_val); + __ or3(data_val, BitData::null_seen_byte_constant(), data_val); + __ stb(data_val, flags_addr); + __ ba(false, done); + __ delayed()->nop(); + __ bind(not_null); + } else { + __ br_null(value, false, Assembler::pn, done); + __ delayed()->nop(); + } load(array, oopDesc::klass_offset_in_bytes(), k_RInfo, T_OBJECT, op->info_for_exception()); load(value, oopDesc::klass_offset_in_bytes(), klass_RInfo, T_OBJECT, NULL); // get instance klass load(k_RInfo, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc), k_RInfo, T_OBJECT, NULL); // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, &done, stub->entry(), NULL); + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, success_target, failure_target, NULL); // call out-of-line instance of __ check_klass_subtype_slow_path(...): assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); __ delayed()->nop(); __ cmp(G3, 0); - __ br(Assembler::equal, false, Assembler::pn, *stub->entry()); + __ br(Assembler::equal, false, Assembler::pn, *failure_target); __ delayed()->nop(); - __ bind(done); - } else if (op->code() == lir_checkcast) { - // we always need a stub for the failure case. - CodeStub* stub = op->stub(); - Register obj = op->object()->as_register(); - Register k_RInfo = op->tmp1()->as_register(); - Register klass_RInfo = op->tmp2()->as_register(); - Register dst = op->result_opr()->as_register(); - Register Rtmp1 = op->tmp3()->as_register(); - ciKlass* k = op->klass(); + // fall through to the success case - if (obj == k_RInfo) { - k_RInfo = klass_RInfo; - klass_RInfo = obj; - } - if (op->profiled_method() != NULL) { - ciMethod* method = op->profiled_method(); - int bci = op->profiled_bci(); - - // We need two temporaries to perform this operation on SPARC, - // so to keep things simple we perform a redundant test here - Label profile_done; - __ cmp(obj, 0); - __ br(Assembler::notEqual, false, Assembler::pn, profile_done); - __ delayed()->nop(); - // Object is null; update methodDataOop - ciMethodData* md = method->method_data(); - if (md == NULL) { - bailout("out of memory building methodDataOop"); - return; - } - ciProfileData* data = md->bci_to_data(bci); - assert(data != NULL, "need data for checkcast"); - assert(data->is_BitData(), "need BitData for checkcast"); - Register mdo = k_RInfo; - Register data_val = Rtmp1; + if (op->should_profile()) { + Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1; + assert_different_registers(value, mdo, recv, tmp1); + __ bind(profile_cast_success); jobject2reg(md->constant_encoding(), mdo); - - int mdo_offset_bias = 0; - if (!Assembler::is_simm13(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) { - // The offset is large so bias the mdo by the base of the slot so - // that the ld can use simm13s to reference the slots of the data - mdo_offset_bias = md->byte_offset_of_slot(data, DataLayout::header_offset()); - __ set(mdo_offset_bias, data_val); - __ add(mdo, data_val, mdo); + if (mdo_offset_bias > 0) { + __ set(mdo_offset_bias, tmp1); + __ add(mdo, tmp1, mdo); } - - - Address flags_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias); - __ ldub(flags_addr, data_val); - __ or3(data_val, BitData::null_seen_byte_constant(), data_val); - __ stb(data_val, flags_addr); - __ bind(profile_done); - } - - Label done; - // patching may screw with our temporaries on sparc, - // so let's do it before loading the class - if (k->is_loaded()) { - jobject2reg(k->constant_encoding(), k_RInfo); - } else { - jobject2reg_with_patching(k_RInfo, op->info_for_patch()); - } - assert(obj != k_RInfo, "must be different"); - __ cmp(obj, 0); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); - - // get object class - // not a safepoint as obj null check happens earlier - load(obj, oopDesc::klass_offset_in_bytes(), klass_RInfo, T_OBJECT, NULL); - if (op->fast_check()) { - assert_different_registers(klass_RInfo, k_RInfo); - __ cmp(k_RInfo, klass_RInfo); - __ br(Assembler::notEqual, false, Assembler::pt, *stub->entry()); + load(Address(value, oopDesc::klass_offset_in_bytes()), recv, T_OBJECT); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &done); + __ ba(false, done); __ delayed()->nop(); - __ bind(done); - } else { - bool need_slow_path = true; - if (k->is_loaded()) { - if (k->super_check_offset() != sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()) - need_slow_path = false; - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, noreg, - (need_slow_path ? &done : NULL), - stub->entry(), NULL, - RegisterOrConstant(k->super_check_offset())); - } else { - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, - &done, stub->entry(), NULL); + // Cast failure case + __ bind(profile_cast_failure); + jobject2reg(md->constant_encoding(), mdo); + if (mdo_offset_bias > 0) { + __ set(mdo_offset_bias, tmp1); + __ add(mdo, tmp1, mdo); } - if (need_slow_path) { - // call out-of-line instance of __ check_klass_subtype_slow_path(...): - assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); - __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ cmp(G3, 0); - __ br(Assembler::equal, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } - __ bind(done); + Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias); + __ ld_ptr(data_addr, tmp1); + __ sub(tmp1, DataLayout::counter_increment, tmp1); + __ st_ptr(tmp1, data_addr); + __ ba(false, *stub->entry()); + __ delayed()->nop(); } + __ bind(done); + } else if (code == lir_checkcast) { + Register obj = op->object()->as_register(); + Register dst = op->result_opr()->as_register(); + Label success; + emit_typecheck_helper(op, &success, op->stub()->entry(), &success); + __ bind(success); __ mov(obj, dst); } else if (code == lir_instanceof) { Register obj = op->object()->as_register(); - Register k_RInfo = op->tmp1()->as_register(); - Register klass_RInfo = op->tmp2()->as_register(); Register dst = op->result_opr()->as_register(); - Register Rtmp1 = op->tmp3()->as_register(); - ciKlass* k = op->klass(); - - Label done; - if (obj == k_RInfo) { - k_RInfo = klass_RInfo; - klass_RInfo = obj; - } - // patching may screw with our temporaries on sparc, - // so let's do it before loading the class - if (k->is_loaded()) { - jobject2reg(k->constant_encoding(), k_RInfo); - } else { - jobject2reg_with_patching(k_RInfo, op->info_for_patch()); - } - assert(obj != k_RInfo, "must be different"); - __ cmp(obj, 0); - __ br(Assembler::equal, true, Assembler::pn, done); - __ delayed()->set(0, dst); - - // get object class - // not a safepoint as obj null check happens earlier - load(obj, oopDesc::klass_offset_in_bytes(), klass_RInfo, T_OBJECT, NULL); - if (op->fast_check()) { - __ cmp(k_RInfo, klass_RInfo); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - __ set(0, dst); - __ bind(done); - } else { - bool need_slow_path = true; - if (k->is_loaded()) { - if (k->super_check_offset() != sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()) - need_slow_path = false; - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, noreg, - (need_slow_path ? &done : NULL), - (need_slow_path ? &done : NULL), NULL, - RegisterOrConstant(k->super_check_offset()), - dst); - } else { - assert(dst != klass_RInfo && dst != k_RInfo, "need 3 registers"); - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, dst, - &done, &done, NULL, - RegisterOrConstant(-1), - dst); - } - if (need_slow_path) { - // call out-of-line instance of __ check_klass_subtype_slow_path(...): - assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); - __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ mov(G3, dst); - } - __ bind(done); - } + Label success, failure, done; + emit_typecheck_helper(op, &success, &failure, &failure); + __ bind(failure); + __ set(0, dst); + __ ba(false, done); + __ delayed()->nop(); + __ bind(success); + __ set(1, dst); + __ bind(done); } else { ShouldNotReachHere(); } @@ -2776,9 +2880,14 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { ciProfileData* data = md->bci_to_data(bci); assert(data->is_CounterData(), "need CounterData for calls"); assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); - assert(op->tmp1()->is_single_cpu(), "tmp1 must be allocated"); Register mdo = op->mdo()->as_register(); +#ifdef _LP64 + assert(op->tmp1()->is_double_cpu(), "tmp1 must be allocated"); + Register tmp1 = op->tmp1()->as_register_lo(); +#else + assert(op->tmp1()->is_single_cpu(), "tmp1 must be allocated"); Register tmp1 = op->tmp1()->as_register(); +#endif jobject2reg(md->constant_encoding(), mdo); int mdo_offset_bias = 0; if (!Assembler::is_simm13(md->byte_offset_of_slot(data, CounterData::count_offset()) + @@ -2795,13 +2904,13 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { // Perform additional virtual call profiling for invokevirtual and // invokeinterface bytecodes if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) && - Tier1ProfileVirtualCalls) { + C1ProfileVirtualCalls) { assert(op->recv()->is_single_cpu(), "recv must be allocated"); Register recv = op->recv()->as_register(); assert_different_registers(mdo, tmp1, recv); assert(data->is_VirtualCallData(), "need VirtualCallData for virtual calls"); ciKlass* known_klass = op->known_holder(); - if (Tier1OptimizeVirtualCallProfiling && known_klass != NULL) { + if (C1OptimizeVirtualCallProfiling && known_klass != NULL) { // We know the type that will be seen at this call site; we can // statically update the methodDataOop rather than needing to do // dynamic tests on the receiver type @@ -2816,9 +2925,9 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias); - __ lduw(data_addr, tmp1); + __ ld_ptr(data_addr, tmp1); __ add(tmp1, DataLayout::counter_increment, tmp1); - __ stw(tmp1, data_addr); + __ st_ptr(tmp1, data_addr); return; } } @@ -2837,70 +2946,32 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { __ st_ptr(tmp1, recv_addr); Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias); - __ lduw(data_addr, tmp1); + __ ld_ptr(data_addr, tmp1); __ add(tmp1, DataLayout::counter_increment, tmp1); - __ stw(tmp1, data_addr); + __ st_ptr(tmp1, data_addr); return; } } } else { load(Address(recv, oopDesc::klass_offset_in_bytes()), recv, T_OBJECT); Label update_done; - uint i; - for (i = 0; i < VirtualCallData::row_limit(); i++) { - Label next_test; - // See if the receiver is receiver[n]. - Address receiver_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) - - mdo_offset_bias); - __ ld_ptr(receiver_addr, tmp1); - __ verify_oop(tmp1); - __ cmp(recv, tmp1); - __ brx(Assembler::notEqual, false, Assembler::pt, next_test); - __ delayed()->nop(); - Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - - mdo_offset_bias); - __ lduw(data_addr, tmp1); - __ add(tmp1, DataLayout::counter_increment, tmp1); - __ stw(tmp1, data_addr); - __ br(Assembler::always, false, Assembler::pt, update_done); - __ delayed()->nop(); - __ bind(next_test); - } - - // Didn't find receiver; find next empty slot and fill it in - for (i = 0; i < VirtualCallData::row_limit(); i++) { - Label next_test; - Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) - - mdo_offset_bias); - load(recv_addr, tmp1, T_OBJECT); - __ tst(tmp1); - __ brx(Assembler::notEqual, false, Assembler::pt, next_test); - __ delayed()->nop(); - __ st_ptr(recv, recv_addr); - __ set(DataLayout::counter_increment, tmp1); - __ st_ptr(tmp1, mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - - mdo_offset_bias); - __ br(Assembler::always, false, Assembler::pt, update_done); - __ delayed()->nop(); - __ bind(next_test); - } + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &update_done); // Receiver did not match any saved receiver and there is no empty row for it. // Increment total counter to indicate polymorphic case. - __ lduw(counter_addr, tmp1); + __ ld_ptr(counter_addr, tmp1); __ add(tmp1, DataLayout::counter_increment, tmp1); - __ stw(tmp1, counter_addr); + __ st_ptr(tmp1, counter_addr); __ bind(update_done); } } else { // Static call - __ lduw(counter_addr, tmp1); + __ ld_ptr(counter_addr, tmp1); __ add(tmp1, DataLayout::counter_increment, tmp1); - __ stw(tmp1, counter_addr); + __ st_ptr(tmp1, counter_addr); } } - void LIR_Assembler::align_backward_branch_target() { __ align(OptoLoopAlignment); } @@ -3093,31 +3164,36 @@ void LIR_Assembler::membar_release() { // no-op on TSO } -// Macro to Pack two sequential registers containing 32 bit values +// Pack two sequential registers containing 32 bit values // into a single 64 bit register. -// rs and rs->successor() are packed into rd -// rd and rs may be the same register. -// Note: rs and rs->successor() are destroyed. -void LIR_Assembler::pack64( Register rs, Register rd ) { +// src and src->successor() are packed into dst +// src and dst may be the same register. +// Note: src is destroyed +void LIR_Assembler::pack64(LIR_Opr src, LIR_Opr dst) { + Register rs = src->as_register(); + Register rd = dst->as_register_lo(); __ sllx(rs, 32, rs); __ srl(rs->successor(), 0, rs->successor()); __ or3(rs, rs->successor(), rd); } -// Macro to unpack a 64 bit value in a register into +// Unpack a 64 bit value in a register into // two sequential registers. -// rd is unpacked into rd and rd->successor() -void LIR_Assembler::unpack64( Register rd ) { - __ mov(rd, rd->successor()); - __ srax(rd, 32, rd); - __ sra(rd->successor(), 0, rd->successor()); +// src is unpacked into dst and dst->successor() +void LIR_Assembler::unpack64(LIR_Opr src, LIR_Opr dst) { + Register rs = src->as_register_lo(); + Register rd = dst->as_register_hi(); + assert_different_registers(rs, rd, rd->successor()); + __ srlx(rs, 32, rd); + __ srl (rs, 0, rd->successor()); } void LIR_Assembler::leal(LIR_Opr addr_opr, LIR_Opr dest) { LIR_Address* addr = addr_opr->as_address_ptr(); assert(addr->index()->is_illegal() && addr->scale() == LIR_Address::times_1 && Assembler::is_simm13(addr->disp()), "can't handle complex addresses yet"); - __ add(addr->base()->as_register(), addr->disp(), dest->as_register()); + + __ add(addr->base()->as_pointer_register(), addr->disp(), dest->as_pointer_register()); } @@ -3188,11 +3264,36 @@ void LIR_Assembler::peephole(LIR_List* lir) { tty->cr(); } #endif - continue; + } else { + LIR_Op* delay_op = new LIR_OpDelay(new LIR_Op0(lir_nop), op->as_OpJavaCall()->info()); + inst->insert_before(i + 1, delay_op); + i++; } - LIR_Op* delay_op = new LIR_OpDelay(new LIR_Op0(lir_nop), op->as_OpJavaCall()->info()); - inst->insert_before(i + 1, delay_op); +#if defined(TIERED) && !defined(_LP64) + // fixup the return value from G1 to O0/O1 for long returns. + // It's done here instead of in LIRGenerator because there's + // such a mismatch between the single reg and double reg + // calling convention. + LIR_OpJavaCall* callop = op->as_OpJavaCall(); + if (callop->result_opr() == FrameMap::out_long_opr) { + LIR_OpJavaCall* call; + LIR_OprList* arguments = new LIR_OprList(callop->arguments()->length()); + for (int a = 0; a < arguments->length(); a++) { + arguments[a] = callop->arguments()[a]; + } + if (op->code() == lir_virtual_call) { + call = new LIR_OpJavaCall(op->code(), callop->method(), callop->receiver(), FrameMap::g1_long_single_opr, + callop->vtable_offset(), arguments, callop->info()); + } else { + call = new LIR_OpJavaCall(op->code(), callop->method(), callop->receiver(), FrameMap::g1_long_single_opr, + callop->addr(), arguments, callop->info()); + } + inst->at_put(i - 1, call); + inst->insert_before(i + 1, new LIR_Op1(lir_unpack64, FrameMap::g1_long_single_opr, callop->result_opr(), + T_LONG, lir_patch_none, NULL)); + } +#endif break; } } diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp index aa12c090eb5..f6f715408e4 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,9 +71,16 @@ static bool is_single_instruction(LIR_Op* op); + // Record the type of the receiver in ReceiverTypeData + void type_profile_helper(Register mdo, int mdo_offset_bias, + ciMethodData *md, ciProfileData *data, + Register recv, Register tmp1, Label* update_done); + // Setup pointers to MDO, MDO slot, also compute offset bias to access the slot. + void setup_md_access(ciMethod* method, int bci, + ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias); public: - void pack64( Register rs, Register rd ); - void unpack64( Register rd ); + void pack64(LIR_Opr src, LIR_Opr dst); + void unpack64(LIR_Opr src, LIR_Opr dst); enum { #ifdef _LP64 diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp index 04a8be9c431..dbdf2027dfe 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -227,29 +227,37 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o } } +LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { + LIR_Opr r; + if (type == T_LONG) { + r = LIR_OprFact::longConst(x); + } else if (type == T_INT) { + r = LIR_OprFact::intConst(x); + } else { + ShouldNotReachHere(); + } + if (!Assembler::is_simm13(x)) { + LIR_Opr tmp = new_register(type); + __ move(r, tmp); + return tmp; + } + return r; +} -void LIRGenerator::increment_counter(address counter, int step) { +void LIRGenerator::increment_counter(address counter, BasicType type, int step) { LIR_Opr pointer = new_pointer_register(); __ move(LIR_OprFact::intptrConst(counter), pointer); - LIR_Address* addr = new LIR_Address(pointer, T_INT); + LIR_Address* addr = new LIR_Address(pointer, type); increment_counter(addr, step); } void LIRGenerator::increment_counter(LIR_Address* addr, int step) { - LIR_Opr temp = new_register(T_INT); + LIR_Opr temp = new_register(addr->type()); __ move(addr, temp); - LIR_Opr c = LIR_OprFact::intConst(step); - if (Assembler::is_simm13(step)) { - __ add(temp, c, temp); - } else { - LIR_Opr temp2 = new_register(T_INT); - __ move(c, temp2); - __ add(temp, temp2, temp); - } + __ add(temp, load_immediate(step, addr->type()), temp); __ move(temp, addr); } - void LIRGenerator::cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info) { LIR_Opr o7opr = FrameMap::O7_opr; __ load(new LIR_Address(base, disp, T_INT), o7opr, info); @@ -611,7 +619,6 @@ void LIRGenerator::do_CompareOp(CompareOp* x) { left.load_item(); right.load_item(); LIR_Opr reg = rlock_result(x); - if (x->x()->type()->is_float_kind()) { Bytecodes::Code code = x->op(); __ fcmp2int(left.result(), right.result(), reg, (code == Bytecodes::_fcmpl || code == Bytecodes::_dcmpl)); @@ -1040,7 +1047,9 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) { LIR_Opr tmp1 = FrameMap::G1_oop_opr; LIR_Opr tmp2 = FrameMap::G3_oop_opr; LIR_Opr tmp3 = FrameMap::G4_oop_opr; - __ instanceof(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, x->direct_compare(), patching_info); + __ instanceof(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, + x->direct_compare(), patching_info, + x->profiled_method(), x->profiled_bci()); } @@ -1089,12 +1098,12 @@ void LIRGenerator::do_If(If* x) { // add safepoint before generating condition code so it can be recomputed if (x->is_safepoint()) { // increment backedge counter if needed - increment_backedge_counter(state_for(x, x->state_before())); - + increment_backedge_counter(state_for(x, x->state_before()), x->profiled_bci()); __ safepoint(new_register(T_INT), state_for(x, x->state_before())); } __ cmp(lir_cond(cond), left, right); + // Generate branch profiling. Profiling code doesn't kill flags. profile_branch(x, cond); move_to_phi(x->state()); if (x->x()->type()->is_float_kind()) { diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 3a4ebb94e58..649e9b12388 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -465,12 +465,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { break; -#ifdef TIERED case counter_overflow_id: - // G4 contains bci - oop_maps = generate_stub_call(sasm, noreg, CAST_FROM_FN_PTR(address, counter_overflow), G4); + // G4 contains bci, G5 contains method + oop_maps = generate_stub_call(sasm, noreg, CAST_FROM_FN_PTR(address, counter_overflow), G4, G5); break; -#endif // TIERED case new_type_array_id: case new_object_array_id: diff --git a/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp index 16dbacbae23..c1ca004f1ff 100644 --- a/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,14 +34,7 @@ define_pd_global(bool, ProfileTraps, false); define_pd_global(bool, UseOnStackReplacement, true ); define_pd_global(bool, TieredCompilation, false); define_pd_global(intx, CompileThreshold, 1000 ); // Design center runs on 1.3.1 -define_pd_global(intx, Tier2CompileThreshold, 1500 ); -define_pd_global(intx, Tier3CompileThreshold, 2000 ); -define_pd_global(intx, Tier4CompileThreshold, 2500 ); - define_pd_global(intx, BackEdgeThreshold, 100000); -define_pd_global(intx, Tier2BackEdgeThreshold, 100000); -define_pd_global(intx, Tier3BackEdgeThreshold, 100000); -define_pd_global(intx, Tier4BackEdgeThreshold, 100000); define_pd_global(intx, OnStackReplacePercentage, 1400 ); define_pd_global(bool, UseTLAB, true ); diff --git a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp index a494cfd6325..cb54d3ba767 100644 --- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,21 +37,8 @@ define_pd_global(bool, ProfileInterpreter, false); define_pd_global(bool, ProfileInterpreter, true); #endif // CC_INTERP define_pd_global(bool, TieredCompilation, false); -#ifdef TIERED -define_pd_global(intx, CompileThreshold, 1000); -define_pd_global(intx, BackEdgeThreshold, 14000); -#else define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, BackEdgeThreshold, 140000); -#endif // TIERED - -define_pd_global(intx, Tier2CompileThreshold, 10000); // unused level -define_pd_global(intx, Tier3CompileThreshold, 10000); -define_pd_global(intx, Tier4CompileThreshold, 40000); - -define_pd_global(intx, Tier2BackEdgeThreshold, 100000); -define_pd_global(intx, Tier3BackEdgeThreshold, 100000); -define_pd_global(intx, Tier4BackEdgeThreshold, 100000); define_pd_global(intx, OnStackReplacePercentage, 140); define_pd_global(intx, ConditionalMoveLimit, 4); diff --git a/hotspot/src/cpu/sparc/vm/codeBuffer_sparc.hpp b/hotspot/src/cpu/sparc/vm/codeBuffer_sparc.hpp index a4025cc90ce..258ff281e7e 100644 --- a/hotspot/src/cpu/sparc/vm/codeBuffer_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/codeBuffer_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,5 +30,5 @@ public: // Heuristic for pre-packing the pt/pn bit of a predicted branch. bool is_backward_branch(Label& L) { - return L.is_bound() && code_end() <= locator_address(L.loc()); + return L.is_bound() && insts_end() <= locator_address(L.loc()); } diff --git a/hotspot/src/cpu/sparc/vm/frame_sparc.cpp b/hotspot/src/cpu/sparc/vm/frame_sparc.cpp index 5e573155743..1ee91aedae0 100644 --- a/hotspot/src/cpu/sparc/vm/frame_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/frame_sparc.cpp @@ -253,11 +253,12 @@ bool frame::safe_for_sender(JavaThread *thread) { } // Could just be some random pointer within the codeBlob - if (!sender.cb()->instructions_contains(sender_pc)) return false; + if (!sender.cb()->code_contains(sender_pc)) { + return false; + } // We should never be able to see an adapter if the current frame is something from code cache - - if ( sender_blob->is_adapter_blob()) { + if (sender_blob->is_adapter_blob()) { return false; } diff --git a/hotspot/src/cpu/sparc/vm/frame_sparc.hpp b/hotspot/src/cpu/sparc/vm/frame_sparc.hpp index 6c50cf75ae4..15a07f8492f 100644 --- a/hotspot/src/cpu/sparc/vm/frame_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/frame_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -263,8 +263,7 @@ }; private: - - constantPoolCacheOop* frame::interpreter_frame_cpoolcache_addr() const; + constantPoolCacheOop* interpreter_frame_cpoolcache_addr() const; #ifndef CC_INTERP diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index 179d459eb10..91c3bc09fa0 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -2431,3 +2431,20 @@ void InterpreterMacroAssembler::restore_return_value( TosState state, bool is_na } #endif // CC_INTERP } + +// Jump if ((*counter_addr += increment) & mask) satisfies the condition. +void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, + int increment, int mask, + Register scratch1, Register scratch2, + Condition cond, Label *where) { + ld(counter_addr, scratch1); + add(scratch1, increment, scratch1); + if (is_simm13(mask)) { + andcc(scratch1, mask, G0); + } else { + set(mask, scratch2); + andcc(scratch1, scratch2, G0); + } + br(cond, false, Assembler::pn, *where); + delayed()->st(scratch1, counter_addr); +} diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp index 66a60635e40..b893f9413a1 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp @@ -278,6 +278,10 @@ class InterpreterMacroAssembler: public MacroAssembler { void increment_mdp_data_at(Register reg, int constant, Register bumped_count, Register scratch2, bool decrement = false); + void increment_mask_and_jump(Address counter_addr, + int increment, int mask, + Register scratch1, Register scratch2, + Condition cond, Label *where); void set_mdp_flag_at(int flag_constant, Register scratch); void test_mdp_data_at(int offset, Register value, Label& not_equal_continue, Register scratch); @@ -321,4 +325,5 @@ class InterpreterMacroAssembler: public MacroAssembler { void save_return_value(TosState state, bool is_native_call); void restore_return_value(TosState state, bool is_native_call); + }; diff --git a/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp b/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp index 7bb12c1ad9d..f390efff1b9 100644 --- a/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,10 +50,10 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { default: ShouldNotReachHere(); } ResourceMark rm; - BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE*wordSize); - address fast_entry = b->instructions_begin(); - CodeBuffer cbuf(fast_entry, b->instructions_size()); + BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize); + CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); + address fast_entry = __ pc(); Label label1, label2; @@ -129,10 +129,10 @@ address JNI_FastGetField::generate_fast_get_int_field() { address JNI_FastGetField::generate_fast_get_long_field() { const char *name = "jni_fast_GetLongField"; ResourceMark rm; - BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE*wordSize); - address fast_entry = b->instructions_begin(); - CodeBuffer cbuf(fast_entry, b->instructions_size()); + BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize); + CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); + address fast_entry = __ pc(); Label label1, label2; @@ -201,10 +201,10 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { default: ShouldNotReachHere(); } ResourceMark rm; - BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE*wordSize); - address fast_entry = b->instructions_begin(); - CodeBuffer cbuf(fast_entry, b->instructions_size()); + BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize); + CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); + address fast_entry = __ pc(); Label label1, label2; diff --git a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp index 37b4bb89107..3c578c95e1f 100644 --- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp @@ -193,17 +193,17 @@ void NativeCall::test() { a->call( a->pc(), relocInfo::none ); a->delayed()->nop(); - nc = nativeCall_at( cb.code_begin() ); + nc = nativeCall_at( cb.insts_begin() ); nc->print(); nc = nativeCall_overwriting_at( nc->next_instruction_address() ); for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) { - nc->set_destination( cb.code_begin() + offsets[idx] ); - assert(nc->destination() == (cb.code_begin() + offsets[idx]), "check unit test"); + nc->set_destination( cb.insts_begin() + offsets[idx] ); + assert(nc->destination() == (cb.insts_begin() + offsets[idx]), "check unit test"); nc->print(); } - nc = nativeCall_before( cb.code_begin() + 8 ); + nc = nativeCall_before( cb.insts_begin() + 8 ); nc->print(); VM_Version::revert(); @@ -368,7 +368,7 @@ void NativeMovConstReg::test() { a->sethi(al2, O2); a->add(O2, al2.low10(), O2); - nm = nativeMovConstReg_at( cb.code_begin() ); + nm = nativeMovConstReg_at( cb.insts_begin() ); nm->print(); nm = nativeMovConstReg_at( nm->next_instruction_address() ); @@ -480,7 +480,7 @@ void NativeMovConstRegPatching::test() { a->nop(); a->add(O2, al2.low10(), O2); - nm = nativeMovConstRegPatching_at( cb.code_begin() ); + nm = nativeMovConstRegPatching_at( cb.insts_begin() ); nm->print(); nm = nativeMovConstRegPatching_at( nm->next_instruction_address() ); @@ -616,7 +616,7 @@ void NativeMovRegMem::test() { a->sethi(al2, I3); a->add(I3, al2.low10(), I3); a->stf( FloatRegisterImpl::S, F15, O0, I3 ); idx++; - nm = nativeMovRegMem_at( cb.code_begin() ); + nm = nativeMovRegMem_at( cb.insts_begin() ); nm->print(); nm->set_offset( low10(0) ); nm->print(); @@ -760,7 +760,7 @@ void NativeMovRegMemPatching::test() { a->sethi(al, I3); a->nop(); a->add(I3, al.low10(), I3); a->stf( FloatRegisterImpl::S, F15, O0, I3 ); idx++; - nm = nativeMovRegMemPatching_at( cb.code_begin() ); + nm = nativeMovRegMemPatching_at( cb.insts_begin() ); nm->print(); nm->set_offset( low10(0) ); nm->print(); @@ -849,7 +849,7 @@ void NativeJump::test() { a->jmpl(I3, al.low10(), L3, RelocationHolder::none); a->delayed()->nop(); - nj = nativeJump_at( cb.code_begin() ); + nj = nativeJump_at( cb.insts_begin() ); nj->print(); nj = nativeJump_at( nj->next_instruction_address() ); diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index ee836d6c7b4..bae042e8f66 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -3331,10 +3331,8 @@ void SharedRuntime::generate_deopt_blob() { __ stf(FloatRegisterImpl::D, Freturn0, saved_Freturn0_addr); #if !defined(_LP64) #if defined(COMPILER2) - if (!TieredCompilation) { - // 32-bit 1-register longs return longs in G1 - __ stx(Greturn1, saved_Greturn1_addr); - } + // 32-bit 1-register longs return longs in G1 + __ stx(Greturn1, saved_Greturn1_addr); #endif __ set_last_Java_frame(SP, noreg); __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames), G2_thread, G4deopt_mode); @@ -3347,24 +3345,15 @@ void SharedRuntime::generate_deopt_blob() { __ reset_last_Java_frame(); __ ldf(FloatRegisterImpl::D, saved_Freturn0_addr, Freturn0); - // In tiered we never use C2 to compile methods returning longs so - // the result is where we expect it already. - #if !defined(_LP64) && defined(COMPILER2) // In 32 bit, C2 returns longs in G1 so restore the saved G1 into - // I0/I1 if the return value is long. In the tiered world there is - // a mismatch between how C1 and C2 return longs compiles and so - // currently compilation of methods which return longs is disabled - // for C2 and so is this code. Eventually C1 and C2 will do the - // same thing for longs in the tiered world. - if (!TieredCompilation) { - Label not_long; - __ cmp(O0,T_LONG); - __ br(Assembler::notEqual, false, Assembler::pt, not_long); - __ delayed()->nop(); - __ ldd(saved_Greturn1_addr,I0); - __ bind(not_long); - } + // I0/I1 if the return value is long. + Label not_long; + __ cmp(O0,T_LONG); + __ br(Assembler::notEqual, false, Assembler::pt, not_long); + __ delayed()->nop(); + __ ldd(saved_Greturn1_addr,I0); + __ bind(not_long); #endif __ ret(); __ delayed()->restore(); diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 50c0b5429c0..fc18cf0ee3c 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -677,8 +677,7 @@ static inline void emit2_19(CodeBuffer &cbuf, int f30, int f29, int f25, int f22 (f20 << 20) | (f19 << 19) | (f0 << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); } // Standard Sparc opcode form2 field breakdown @@ -689,8 +688,7 @@ static inline void emit2_22(CodeBuffer &cbuf, int f30, int f25, int f22, int f0 (f25 << 25) | (f22 << 22) | (f0 << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); } // Standard Sparc opcode form3 field breakdown @@ -701,8 +699,7 @@ static inline void emit3(CodeBuffer &cbuf, int f30, int f25, int f19, int f14, i (f14 << 14) | (f5 << 5) | (f0 << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); } // Standard Sparc opcode form3 field breakdown @@ -714,8 +711,7 @@ static inline void emit3_simm13(CodeBuffer &cbuf, int f30, int f25, int f19, int (f14 << 14) | (1 << 13) | // bit to indicate immediate-mode (simm13<<0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); } static inline void emit3_simm10(CodeBuffer &cbuf, int f30, int f25, int f19, int f14, int simm10 ) { @@ -910,9 +906,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te instr |= disp & 0x1FFF; } - uint *code = (uint*)cbuf.code_end(); - *code = instr; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(instr); #ifdef ASSERT { @@ -1532,7 +1526,7 @@ void emit_java_to_interp(CodeBuffer &cbuf ) { // set (empty), G5 // jmp -1 - address mark = cbuf.inst_mark(); // get mark within main instrs section + address mark = cbuf.insts_mark(); // get mark within main instrs section MacroAssembler _masm(&cbuf); @@ -1632,7 +1626,7 @@ uint size_deopt_handler() { // Emit exception handler code. int emit_exception_handler(CodeBuffer& cbuf) { Register temp_reg = G3; - AddressLiteral exception_blob(OptoRuntime::exception_blob()->instructions_begin()); + AddressLiteral exception_blob(OptoRuntime::exception_blob()->entry_point()); MacroAssembler _masm(&cbuf); address base = @@ -2292,8 +2286,7 @@ encode %{ (0 << 13) | // select register move ($pcc$$constant << 11) | // cc1, cc0 bits for 'icc' or 'xcc' ($src$$reg << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); %} enc_class enc_cmov_imm( cmpOp cmp, iRegI dst, immI11 src, immI pcc ) %{ @@ -2306,8 +2299,7 @@ encode %{ (1 << 13) | // select immediate move ($pcc$$constant << 11) | // cc1, cc0 bits for 'icc' (simm11 << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); %} enc_class enc_cmov_reg_f( cmpOpF cmp, iRegI dst, iRegI src, flagsRegF fcc ) %{ @@ -2319,8 +2311,7 @@ encode %{ (0 << 13) | // select register move ($fcc$$reg << 11) | // cc1, cc0 bits for fcc0-fcc3 ($src$$reg << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); %} enc_class enc_cmov_imm_f( cmpOp cmp, iRegI dst, immI11 src, flagsRegF fcc ) %{ @@ -2333,8 +2324,7 @@ encode %{ (1 << 13) | // select immediate move ($fcc$$reg << 11) | // cc1, cc0 bits for fcc0-fcc3 (simm11 << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); %} enc_class enc_cmovf_reg( cmpOp cmp, regD dst, regD src, immI pcc ) %{ @@ -2347,8 +2337,7 @@ encode %{ ($pcc$$constant << 11) | // cc1-cc0 bits for 'icc' or 'xcc' ($primary << 5) | // select single, double or quad ($src$$reg << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); %} enc_class enc_cmovff_reg( cmpOpF cmp, flagsRegF fcc, regD dst, regD src ) %{ @@ -2360,8 +2349,7 @@ encode %{ ($fcc$$reg << 11) | // cc2-cc0 bits for 'fccX' ($primary << 5) | // select single, double or quad ($src$$reg << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); %} // Used by the MIN/MAX encodings. Same as a CMOV, but @@ -2375,8 +2363,7 @@ encode %{ (0 << 13) | // select register move (0 << 11) | // cc1, cc0 bits for 'icc' ($src$$reg << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); %} enc_class enc_cmov_reg_minmax_long( iRegL dst, iRegL src ) %{ @@ -2388,8 +2375,7 @@ encode %{ (0 << 13) | // select register move (0 << 11) | // cc1, cc0 bits for 'icc' ($src$$reg << 0); - *((int*)(cbuf.code_end())) = op; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32(op); %} // Utility encoding for loading a 64 bit Pointer into a register @@ -3055,7 +3041,7 @@ enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, notemp_iRegI r %} enc_class enc_rethrow() %{ - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); Register temp_reg = G3; AddressLiteral rethrow_stub(OptoRuntime::rethrow_stub()); assert(temp_reg != reg_to_register_object(R_I0_num), "temp must not break oop_reg"); @@ -3076,23 +3062,17 @@ enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, notemp_iRegI r enc_class emit_mem_nop() %{ // Generates the instruction LDUXA [o6,g0],#0x82,g0 - unsigned int *code = (unsigned int*)cbuf.code_end(); - *code = (unsigned int)0xc0839040; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32((unsigned int) 0xc0839040); %} enc_class emit_fadd_nop() %{ // Generates the instruction FMOVS f31,f31 - unsigned int *code = (unsigned int*)cbuf.code_end(); - *code = (unsigned int)0xbfa0003f; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32((unsigned int) 0xbfa0003f); %} enc_class emit_br_nop() %{ // Generates the instruction BPN,PN . - unsigned int *code = (unsigned int*)cbuf.code_end(); - *code = (unsigned int)0x00400000; - cbuf.set_code_end(cbuf.code_end() + BytesPerInstWord); + cbuf.insts()->emit_int32((unsigned int) 0x00400000); %} enc_class enc_membar_acquire %{ diff --git a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp index 99a7eebf4c4..7c64ab30fd5 100644 --- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp @@ -1587,6 +1587,229 @@ class StubGenerator: public StubCodeGenerator { return start; } + // + // Generate stub for disjoint short fill. If "aligned" is true, the + // "to" address is assumed to be heapword aligned. + // + // Arguments for generated stub: + // to: O0 + // value: O1 + // count: O2 treated as signed + // + address generate_fill(BasicType t, bool aligned, const char* name) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + + const Register to = O0; // source array address + const Register value = O1; // fill value + const Register count = O2; // elements count + // O3 is used as a temp register + + assert_clean_int(count, O3); // Make sure 'count' is clean int. + + Label L_exit, L_skip_align1, L_skip_align2, L_fill_byte; + Label L_fill_2_bytes, L_fill_elements, L_fill_32_bytes; + + int shift = -1; + switch (t) { + case T_BYTE: + shift = 2; + break; + case T_SHORT: + shift = 1; + break; + case T_INT: + shift = 0; + break; + default: ShouldNotReachHere(); + } + + BLOCK_COMMENT("Entry:"); + + if (t == T_BYTE) { + // Zero extend value + __ and3(value, 0xff, value); + __ sllx(value, 8, O3); + __ or3(value, O3, value); + } + if (t == T_SHORT) { + // Zero extend value + __ sllx(value, 48, value); + __ srlx(value, 48, value); + } + if (t == T_BYTE || t == T_SHORT) { + __ sllx(value, 16, O3); + __ or3(value, O3, value); + } + + __ cmp(count, 2<andcc(count, 1, G0); + + if (!aligned && (t == T_BYTE || t == T_SHORT)) { + // align source address at 4 bytes address boundary + if (t == T_BYTE) { + // One byte misalignment happens only for byte arrays + __ andcc(to, 1, G0); + __ br(Assembler::zero, false, Assembler::pt, L_skip_align1); + __ delayed()->nop(); + __ stb(value, to, 0); + __ inc(to, 1); + __ dec(count, 1); + __ BIND(L_skip_align1); + } + // Two bytes misalignment happens only for byte and short (char) arrays + __ andcc(to, 2, G0); + __ br(Assembler::zero, false, Assembler::pt, L_skip_align2); + __ delayed()->nop(); + __ sth(value, to, 0); + __ inc(to, 2); + __ dec(count, 1 << (shift - 1)); + __ BIND(L_skip_align2); + } +#ifdef _LP64 + if (!aligned) { +#endif + // align to 8 bytes, we know we are 4 byte aligned to start + __ andcc(to, 7, G0); + __ br(Assembler::zero, false, Assembler::pt, L_fill_32_bytes); + __ delayed()->nop(); + __ stw(value, to, 0); + __ inc(to, 4); + __ dec(count, 1 << shift); + __ BIND(L_fill_32_bytes); +#ifdef _LP64 + } +#endif + + if (t == T_INT) { + // Zero extend value + __ srl(value, 0, value); + } + if (t == T_BYTE || t == T_SHORT || t == T_INT) { + __ sllx(value, 32, O3); + __ or3(value, O3, value); + } + + Label L_check_fill_8_bytes; + // Fill 32-byte chunks + __ subcc(count, 8 << shift, count); + __ brx(Assembler::less, false, Assembler::pt, L_check_fill_8_bytes); + __ delayed()->nop(); + + Label L_fill_32_bytes_loop, L_fill_4_bytes; + __ align(16); + __ BIND(L_fill_32_bytes_loop); + + __ stx(value, to, 0); + __ stx(value, to, 8); + __ stx(value, to, 16); + __ stx(value, to, 24); + + __ subcc(count, 8 << shift, count); + __ brx(Assembler::greaterEqual, false, Assembler::pt, L_fill_32_bytes_loop); + __ delayed()->add(to, 32, to); + + __ BIND(L_check_fill_8_bytes); + __ addcc(count, 8 << shift, count); + __ brx(Assembler::zero, false, Assembler::pn, L_exit); + __ delayed()->subcc(count, 1 << (shift + 1), count); + __ brx(Assembler::less, false, Assembler::pn, L_fill_4_bytes); + __ delayed()->andcc(count, 1<add(to, 8, to); + + // fill trailing 4 bytes + __ andcc(count, 1<andcc(count, 1<<(shift-1), G0); + } else { + __ delayed()->nop(); + } + __ stw(value, to, 0); + if (t == T_BYTE || t == T_SHORT) { + __ inc(to, 4); + // fill trailing 2 bytes + __ andcc(count, 1<<(shift-1), G0); // in delay slot of branches + __ BIND(L_fill_2_bytes); + __ brx(Assembler::zero, false, Assembler::pt, L_fill_byte); + __ delayed()->andcc(count, 1, count); + __ sth(value, to, 0); + if (t == T_BYTE) { + __ inc(to, 2); + // fill trailing byte + __ andcc(count, 1, count); // in delay slot of branches + __ BIND(L_fill_byte); + __ brx(Assembler::zero, false, Assembler::pt, L_exit); + __ delayed()->nop(); + __ stb(value, to, 0); + } else { + __ BIND(L_fill_byte); + } + } else { + __ BIND(L_fill_2_bytes); + } + __ BIND(L_exit); + __ retl(); + __ delayed()->nop(); + + // Handle copies less than 8 bytes. Int is handled elsewhere. + if (t == T_BYTE) { + __ BIND(L_fill_elements); + Label L_fill_2, L_fill_4; + // in delay slot __ andcc(count, 1, G0); + __ brx(Assembler::zero, false, Assembler::pt, L_fill_2); + __ delayed()->andcc(count, 2, G0); + __ stb(value, to, 0); + __ inc(to, 1); + __ BIND(L_fill_2); + __ brx(Assembler::zero, false, Assembler::pt, L_fill_4); + __ delayed()->andcc(count, 4, G0); + __ stb(value, to, 0); + __ stb(value, to, 1); + __ inc(to, 2); + __ BIND(L_fill_4); + __ brx(Assembler::zero, false, Assembler::pt, L_exit); + __ delayed()->nop(); + __ stb(value, to, 0); + __ stb(value, to, 1); + __ stb(value, to, 2); + __ retl(); + __ delayed()->stb(value, to, 3); + } + + if (t == T_SHORT) { + Label L_fill_2; + __ BIND(L_fill_elements); + // in delay slot __ andcc(count, 1, G0); + __ brx(Assembler::zero, false, Assembler::pt, L_fill_2); + __ delayed()->andcc(count, 2, G0); + __ sth(value, to, 0); + __ inc(to, 2); + __ BIND(L_fill_2); + __ brx(Assembler::zero, false, Assembler::pt, L_exit); + __ delayed()->nop(); + __ sth(value, to, 0); + __ retl(); + __ delayed()->sth(value, to, 2); + } + return start; + } + // // Generate stub for conjoint short copy. If "aligned" is true, the // "from" and "to" addresses are assumed to be heapword aligned. @@ -2855,6 +3078,13 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy"); StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy"); StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy"); + + StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill"); + StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill"); + StubRoutines::_jint_fill = generate_fill(T_INT, false, "jint_fill"); + StubRoutines::_arrayof_jbyte_fill = generate_fill(T_BYTE, true, "arrayof_jbyte_fill"); + StubRoutines::_arrayof_jshort_fill = generate_fill(T_SHORT, true, "arrayof_jshort_fill"); + StubRoutines::_arrayof_jint_fill = generate_fill(T_INT, true, "arrayof_jint_fill"); } void generate_initial() { diff --git a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp b/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp index 466e30e6249..e02789d2530 100644 --- a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp @@ -43,7 +43,7 @@ enum /* platform_dependent_constants */ { // MethodHandles adapters enum method_handles_platform_dependent_constants { - method_handles_adapters_code_size = 6000 + method_handles_adapters_code_size = 12000 }; class Sparc { diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index 57da8ed2b92..cc05ddb7e96 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -294,35 +294,65 @@ address TemplateInterpreterGenerator::generate_continuation_for(TosState state) // ??: invocation counter // void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { - // Update standard invocation counters - __ increment_invocation_counter(O0, G3_scratch); - if (ProfileInterpreter) { // %%% Merge this into methodDataOop - Address interpreter_invocation_counter(Lmethod, methodOopDesc::interpreter_invocation_counter_offset()); - __ ld(interpreter_invocation_counter, G3_scratch); - __ inc(G3_scratch); - __ st(G3_scratch, interpreter_invocation_counter); - } + // Note: In tiered we increment either counters in methodOop or in MDO depending if we're profiling or not. + if (TieredCompilation) { + const int increment = InvocationCounter::count_increment; + const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; + Label no_mdo, done; + if (ProfileInterpreter) { + // If no method data exists, go to profile_continue. + __ ld_ptr(Lmethod, methodOopDesc::method_data_offset(), G4_scratch); + __ br_null(G4_scratch, false, Assembler::pn, no_mdo); + __ delayed()->nop(); + // Increment counter + Address mdo_invocation_counter(G4_scratch, + in_bytes(methodDataOopDesc::invocation_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, + G3_scratch, Lscratch, + Assembler::zero, overflow); + __ ba(false, done); + __ delayed()->nop(); + } - if (ProfileInterpreter && profile_method != NULL) { - // Test to see if we should create a method data oop - AddressLiteral profile_limit(&InvocationCounter::InterpreterProfileLimit); - __ sethi(profile_limit, G3_scratch); - __ ld(G3_scratch, profile_limit.low10(), G3_scratch); + // Increment counter in methodOop + __ bind(no_mdo); + Address invocation_counter(Lmethod, + in_bytes(methodOopDesc::invocation_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + __ increment_mask_and_jump(invocation_counter, increment, mask, + G3_scratch, Lscratch, + Assembler::zero, overflow); + __ bind(done); + } else { + // Update standard invocation counters + __ increment_invocation_counter(O0, G3_scratch); + if (ProfileInterpreter) { // %%% Merge this into methodDataOop + Address interpreter_invocation_counter(Lmethod,in_bytes(methodOopDesc::interpreter_invocation_counter_offset())); + __ ld(interpreter_invocation_counter, G3_scratch); + __ inc(G3_scratch); + __ st(G3_scratch, interpreter_invocation_counter); + } + + if (ProfileInterpreter && profile_method != NULL) { + // Test to see if we should create a method data oop + AddressLiteral profile_limit((address)&InvocationCounter::InterpreterProfileLimit); + __ load_contents(profile_limit, G3_scratch); + __ cmp(O0, G3_scratch); + __ br(Assembler::lessUnsigned, false, Assembler::pn, *profile_method_continue); + __ delayed()->nop(); + + // if no method data exists, go to profile_method + __ test_method_data_pointer(*profile_method); + } + + AddressLiteral invocation_limit((address)&InvocationCounter::InterpreterInvocationLimit); + __ load_contents(invocation_limit, G3_scratch); __ cmp(O0, G3_scratch); - __ br(Assembler::lessUnsigned, false, Assembler::pn, *profile_method_continue); + __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); __ delayed()->nop(); - - // if no method data exists, go to profile_method - __ test_method_data_pointer(*profile_method); } - AddressLiteral invocation_limit(&InvocationCounter::InterpreterInvocationLimit); - __ sethi(invocation_limit, G3_scratch); - __ ld(G3_scratch, invocation_limit.low10(), G3_scratch); - __ cmp(O0, G3_scratch); - __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); - __ delayed()->nop(); - } // Allocate monitor and lock method (asm interpreter) diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index 7a45489be40..b144985f132 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -1580,6 +1580,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { const Register O0_cur_bcp = O0; __ mov( Lbcp, O0_cur_bcp ); + bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter; if ( increment_invocation_counter_for_backward_branches ) { Label Lforward; @@ -1588,17 +1589,84 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Bump bytecode pointer by displacement (take the branch) __ delayed()->add( O1_disp, Lbcp, Lbcp ); // add to bc addr - // Update Backedge branch separately from invocations - const Register G4_invoke_ctr = G4; - __ increment_backedge_counter(G4_invoke_ctr, G1_scratch); - if (ProfileInterpreter) { - __ test_invocation_counter_for_mdp(G4_invoke_ctr, Lbcp, G3_scratch, Lforward); - if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(O2_bumped_count, O0_cur_bcp, G3_scratch); + if (TieredCompilation) { + Label Lno_mdo, Loverflow; + int increment = InvocationCounter::count_increment; + int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; + if (ProfileInterpreter) { + // If no method data exists, go to profile_continue. + __ ld_ptr(Lmethod, methodOopDesc::method_data_offset(), G4_scratch); + __ br_null(G4_scratch, false, Assembler::pn, Lno_mdo); + __ delayed()->nop(); + + // Increment backedge counter in the MDO + Address mdo_backedge_counter(G4_scratch, in_bytes(methodDataOopDesc::backedge_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, G3_scratch, Lscratch, + Assembler::notZero, &Lforward); + __ ba(false, Loverflow); + __ delayed()->nop(); } + + // If there's no MDO, increment counter in methodOop + __ bind(Lno_mdo); + Address backedge_counter(Lmethod, in_bytes(methodOopDesc::backedge_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + __ increment_mask_and_jump(backedge_counter, increment, mask, G3_scratch, Lscratch, + Assembler::notZero, &Lforward); + __ bind(Loverflow); + + // notify point for loop, pass branch bytecode + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), O0_cur_bcp); + + // Was an OSR adapter generated? + // O0 = osr nmethod + __ br_null(O0, false, Assembler::pn, Lforward); + __ delayed()->nop(); + + // Has the nmethod been invalidated already? + __ ld(O0, nmethod::entry_bci_offset(), O2); + __ cmp(O2, InvalidOSREntryBci); + __ br(Assembler::equal, false, Assembler::pn, Lforward); + __ delayed()->nop(); + + // migrate the interpreter frame off of the stack + + __ mov(G2_thread, L7); + // save nmethod + __ mov(O0, L6); + __ set_last_Java_frame(SP, noreg); + __ call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), L7); + __ reset_last_Java_frame(); + __ mov(L7, G2_thread); + + // move OSR nmethod to I1 + __ mov(L6, I1); + + // OSR buffer to I0 + __ mov(O0, I0); + + // remove the interpreter frame + __ restore(I5_savedSP, 0, SP); + + // Jump to the osr code. + __ ld_ptr(O1, nmethod::osr_entry_point_offset(), O2); + __ jmp(O2, G0); + __ delayed()->nop(); + } else { - if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(G4_invoke_ctr, O0_cur_bcp, G3_scratch); + // Update Backedge branch separately from invocations + const Register G4_invoke_ctr = G4; + __ increment_backedge_counter(G4_invoke_ctr, G1_scratch); + if (ProfileInterpreter) { + __ test_invocation_counter_for_mdp(G4_invoke_ctr, Lbcp, G3_scratch, Lforward); + if (UseOnStackReplacement) { + __ test_backedge_count_for_osr(O2_bumped_count, O0_cur_bcp, G3_scratch); + } + } else { + if (UseOnStackReplacement) { + __ test_backedge_count_for_osr(G4_invoke_ctr, O0_cur_bcp, G3_scratch); + } } } diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index ba44fe6a52b..ca8a0ddafa8 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -112,6 +112,11 @@ void VM_Version::initialize() { } } +#ifdef COMPILER2 + // Currently not supported anywhere. + FLAG_SET_DEFAULT(UseFPUForSpilling, false); +#endif + char buf[512]; jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s", (has_v8() ? ", has_v8" : ""), diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index bb7517f533d..4f43327d304 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -4993,19 +4993,22 @@ void MacroAssembler::debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rd ttyLocker ttyl; tty->print_cr("eip = 0x%08x", eip); #ifndef PRODUCT - tty->cr(); - findpc(eip); - tty->cr(); + if ((WizardMode || Verbose) && PrintMiscellaneous) { + tty->cr(); + findpc(eip); + tty->cr(); + } #endif - tty->print_cr("rax, = 0x%08x", rax); - tty->print_cr("rbx, = 0x%08x", rbx); + tty->print_cr("rax = 0x%08x", rax); + tty->print_cr("rbx = 0x%08x", rbx); tty->print_cr("rcx = 0x%08x", rcx); tty->print_cr("rdx = 0x%08x", rdx); tty->print_cr("rdi = 0x%08x", rdi); tty->print_cr("rsi = 0x%08x", rsi); - tty->print_cr("rbp, = 0x%08x", rbp); + tty->print_cr("rbp = 0x%08x", rbp); tty->print_cr("rsp = 0x%08x", rsp); BREAKPOINT; + assert(false, "start up GDB"); } } else { ttyLocker ttyl; @@ -7677,11 +7680,19 @@ RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_ad movptr(tmp, ExternalAddress((address) delayed_value_addr)); #ifdef ASSERT - Label L; - testptr(tmp, tmp); - jccb(Assembler::notZero, L); - hlt(); - bind(L); + { Label L; + testptr(tmp, tmp); + if (WizardMode) { + jcc(Assembler::notZero, L); + char* buf = new char[40]; + sprintf(buf, "DelayedValue="INTPTR_FORMAT, delayed_value_addr[1]); + stop(buf); + } else { + jccb(Assembler::notZero, L); + hlt(); + } + bind(L); + } #endif if (offset != 0) @@ -8767,6 +8778,186 @@ void MacroAssembler::char_arrays_equals(bool is_array_equ, Register ary1, Regist bind(DONE); } +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) block_comment(str) +#endif + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") +void MacroAssembler::generate_fill(BasicType t, bool aligned, + Register to, Register value, Register count, + Register rtmp, XMMRegister xtmp) { + assert_different_registers(to, value, count, rtmp); + Label L_exit, L_skip_align1, L_skip_align2, L_fill_byte; + Label L_fill_2_bytes, L_fill_4_bytes; + + int shift = -1; + switch (t) { + case T_BYTE: + shift = 2; + break; + case T_SHORT: + shift = 1; + break; + case T_INT: + shift = 0; + break; + default: ShouldNotReachHere(); + } + + if (t == T_BYTE) { + andl(value, 0xff); + movl(rtmp, value); + shll(rtmp, 8); + orl(value, rtmp); + } + if (t == T_SHORT) { + andl(value, 0xffff); + } + if (t == T_BYTE || t == T_SHORT) { + movl(rtmp, value); + shll(rtmp, 16); + orl(value, rtmp); + } + + cmpl(count, 2<= 2, "supported cpu only" ); + Label L_fill_32_bytes_loop, L_check_fill_8_bytes, L_fill_8_bytes_loop, L_fill_8_bytes; + // Fill 32-byte chunks + movdl(xtmp, value); + pshufd(xtmp, xtmp, 0); + + subl(count, 8 << shift); + jcc(Assembler::less, L_check_fill_8_bytes); + align(16); + + BIND(L_fill_32_bytes_loop); + + if (UseUnalignedLoadStores) { + movdqu(Address(to, 0), xtmp); + movdqu(Address(to, 16), xtmp); + } else { + movq(Address(to, 0), xtmp); + movq(Address(to, 8), xtmp); + movq(Address(to, 16), xtmp); + movq(Address(to, 24), xtmp); + } + + addptr(to, 32); + subl(count, 8 << shift); + jcc(Assembler::greaterEqual, L_fill_32_bytes_loop); + BIND(L_check_fill_8_bytes); + addl(count, 8 << shift); + jccb(Assembler::zero, L_exit); + jmpb(L_fill_8_bytes); + + // + // length is too short, just fill qwords + // + BIND(L_fill_8_bytes_loop); + movq(Address(to, 0), xtmp); + addptr(to, 8); + BIND(L_fill_8_bytes); + subl(count, 1 << (shift + 1)); + jcc(Assembler::greaterEqual, L_fill_8_bytes_loop); + } + } + // fill trailing 4 bytes + BIND(L_fill_4_bytes); + testl(count, 1<store_parameter(_method->as_register(), 1); ce->store_parameter(_bci, 0); __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::counter_overflow_id))); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - __ jmp(_continuation); } -#endif // TIERED - - RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, bool throw_index_out_of_bounds_exception) diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index 39ca0e2d8bb..3af7df224e6 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -1613,6 +1613,188 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { __ bind(*op->stub()->continuation()); } +void LIR_Assembler::type_profile_helper(Register mdo, + ciMethodData *md, ciProfileData *data, + Register recv, Label* update_done) { + for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) { + Label next_test; + // See if the receiver is receiver[n]. + __ cmpptr(recv, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)))); + __ jccb(Assembler::notEqual, next_test); + Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i))); + __ addptr(data_addr, DataLayout::counter_increment); + __ jmp(*update_done); + __ bind(next_test); + } + + // Didn't find receiver; find next empty slot and fill it in + for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) { + Label next_test; + Address recv_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i))); + __ cmpptr(recv_addr, (intptr_t)NULL_WORD); + __ jccb(Assembler::notEqual, next_test); + __ movptr(recv_addr, recv); + __ movptr(Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i))), DataLayout::counter_increment); + __ jmp(*update_done); + __ bind(next_test); + } +} + +void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) { + // we always need a stub for the failure case. + CodeStub* stub = op->stub(); + Register obj = op->object()->as_register(); + Register k_RInfo = op->tmp1()->as_register(); + Register klass_RInfo = op->tmp2()->as_register(); + Register dst = op->result_opr()->as_register(); + ciKlass* k = op->klass(); + Register Rtmp1 = noreg; + + // check if it needs to be profiled + ciMethodData* md; + ciProfileData* data; + + if (op->should_profile()) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + int bci = op->profiled_bci(); + md = method->method_data(); + if (md == NULL) { + bailout("out of memory building methodDataOop"); + return; + } + data = md->bci_to_data(bci); + assert(data != NULL, "need data for type check"); + assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); + } + Label profile_cast_success, profile_cast_failure; + Label *success_target = op->should_profile() ? &profile_cast_success : success; + Label *failure_target = op->should_profile() ? &profile_cast_failure : failure; + + if (obj == k_RInfo) { + k_RInfo = dst; + } else if (obj == klass_RInfo) { + klass_RInfo = dst; + } + if (k->is_loaded()) { + select_different_registers(obj, dst, k_RInfo, klass_RInfo); + } else { + Rtmp1 = op->tmp3()->as_register(); + select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1); + } + + assert_different_registers(obj, k_RInfo, klass_RInfo); + if (!k->is_loaded()) { + jobject2reg_with_patching(k_RInfo, op->info_for_patch()); + } else { +#ifdef _LP64 + __ movoop(k_RInfo, k->constant_encoding()); +#endif // _LP64 + } + assert(obj != k_RInfo, "must be different"); + + __ cmpptr(obj, (int32_t)NULL_WORD); + if (op->should_profile()) { + Label not_null; + __ jccb(Assembler::notEqual, not_null); + // Object is null; update MDO and exit + Register mdo = klass_RInfo; + __ movoop(mdo, md->constant_encoding()); + Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset())); + int header_bits = DataLayout::flag_mask_to_header_mask(BitData::null_seen_byte_constant()); + __ orl(data_addr, header_bits); + __ jmp(*obj_is_null); + __ bind(not_null); + } else { + __ jcc(Assembler::equal, *obj_is_null); + } + __ verify_oop(obj); + + if (op->fast_check()) { + // get object class + // not a safepoint as obj null check happens earlier + if (k->is_loaded()) { +#ifdef _LP64 + __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); +#else + __ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding()); +#endif // _LP64 + } else { + __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); + } + __ jcc(Assembler::notEqual, *failure_target); + // successful cast, fall through to profile or jump + } else { + // get object class + // not a safepoint as obj null check happens earlier + __ movptr(klass_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); + if (k->is_loaded()) { + // See if we get an immediate positive hit +#ifdef _LP64 + __ cmpptr(k_RInfo, Address(klass_RInfo, k->super_check_offset())); +#else + __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding()); +#endif // _LP64 + if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) { + __ jcc(Assembler::notEqual, *failure_target); + // successful cast, fall through to profile or jump + } else { + // See if we get an immediate positive hit + __ jcc(Assembler::equal, *success_target); + // check for self +#ifdef _LP64 + __ cmpptr(klass_RInfo, k_RInfo); +#else + __ cmpoop(klass_RInfo, k->constant_encoding()); +#endif // _LP64 + __ jcc(Assembler::equal, *success_target); + + __ push(klass_RInfo); +#ifdef _LP64 + __ push(k_RInfo); +#else + __ pushoop(k->constant_encoding()); +#endif // _LP64 + __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); + __ pop(klass_RInfo); + __ pop(klass_RInfo); + // result is a boolean + __ cmpl(klass_RInfo, 0); + __ jcc(Assembler::equal, *failure_target); + // successful cast, fall through to profile or jump + } + } else { + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, NULL); + // call out-of-line instance of __ check_klass_subtype_slow_path(...): + __ push(klass_RInfo); + __ push(k_RInfo); + __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); + __ pop(klass_RInfo); + __ pop(k_RInfo); + // result is a boolean + __ cmpl(k_RInfo, 0); + __ jcc(Assembler::equal, *failure_target); + // successful cast, fall through to profile or jump + } + } + if (op->should_profile()) { + Register mdo = klass_RInfo, recv = k_RInfo; + __ bind(profile_cast_success); + __ movoop(mdo, md->constant_encoding()); + __ movptr(recv, Address(obj, oopDesc::klass_offset_in_bytes())); + Label update_done; + type_profile_helper(mdo, md, data, recv, success); + __ jmp(*success); + + __ bind(profile_cast_failure); + __ movoop(mdo, md->constant_encoding()); + Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); + __ subptr(counter_addr, DataLayout::counter_increment); + __ jmp(*failure); + } + __ jmp(*success); +} void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { @@ -1625,9 +1807,44 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { Register Rtmp1 = op->tmp3()->as_register(); CodeStub* stub = op->stub(); - Label done; + + // check if it needs to be profiled + ciMethodData* md; + ciProfileData* data; + + if (op->should_profile()) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + int bci = op->profiled_bci(); + md = method->method_data(); + if (md == NULL) { + bailout("out of memory building methodDataOop"); + return; + } + data = md->bci_to_data(bci); + assert(data != NULL, "need data for type check"); + assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); + } + Label profile_cast_success, profile_cast_failure, done; + Label *success_target = op->should_profile() ? &profile_cast_success : &done; + Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); + __ cmpptr(value, (int32_t)NULL_WORD); - __ jcc(Assembler::equal, done); + if (op->should_profile()) { + Label not_null; + __ jccb(Assembler::notEqual, not_null); + // Object is null; update MDO and exit + Register mdo = klass_RInfo; + __ movoop(mdo, md->constant_encoding()); + Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset())); + int header_bits = DataLayout::flag_mask_to_header_mask(BitData::null_seen_byte_constant()); + __ orl(data_addr, header_bits); + __ jmp(done); + __ bind(not_null); + } else { + __ jcc(Assembler::equal, done); + } + add_debug_info_for_null_check_here(op->info_for_exception()); __ movptr(k_RInfo, Address(array, oopDesc::klass_offset_in_bytes())); __ movptr(klass_RInfo, Address(value, oopDesc::klass_offset_in_bytes())); @@ -1635,7 +1852,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { // get instance klass __ movptr(k_RInfo, Address(k_RInfo, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc))); // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, &done, stub->entry(), NULL); + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, NULL); // call out-of-line instance of __ check_klass_subtype_slow_path(...): __ push(klass_RInfo); __ push(k_RInfo); @@ -1644,228 +1861,51 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ pop(k_RInfo); // result is a boolean __ cmpl(k_RInfo, 0); - __ jcc(Assembler::equal, *stub->entry()); - __ bind(done); - } else if (op->code() == lir_checkcast) { - // we always need a stub for the failure case. - CodeStub* stub = op->stub(); - Register obj = op->object()->as_register(); - Register k_RInfo = op->tmp1()->as_register(); - Register klass_RInfo = op->tmp2()->as_register(); - Register dst = op->result_opr()->as_register(); - ciKlass* k = op->klass(); - Register Rtmp1 = noreg; + __ jcc(Assembler::equal, *failure_target); + // fall through to the success case - Label done; - if (obj == k_RInfo) { - k_RInfo = dst; - } else if (obj == klass_RInfo) { - klass_RInfo = dst; - } - if (k->is_loaded()) { - select_different_registers(obj, dst, k_RInfo, klass_RInfo); - } else { - Rtmp1 = op->tmp3()->as_register(); - select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1); - } - - assert_different_registers(obj, k_RInfo, klass_RInfo); - if (!k->is_loaded()) { - jobject2reg_with_patching(k_RInfo, op->info_for_patch()); - } else { -#ifdef _LP64 - __ movoop(k_RInfo, k->constant_encoding()); -#else - k_RInfo = noreg; -#endif // _LP64 - } - assert(obj != k_RInfo, "must be different"); - __ cmpptr(obj, (int32_t)NULL_WORD); - if (op->profiled_method() != NULL) { - ciMethod* method = op->profiled_method(); - int bci = op->profiled_bci(); - - Label profile_done; - __ jcc(Assembler::notEqual, profile_done); - // Object is null; update methodDataOop - ciMethodData* md = method->method_data(); - if (md == NULL) { - bailout("out of memory building methodDataOop"); - return; - } - ciProfileData* data = md->bci_to_data(bci); - assert(data != NULL, "need data for checkcast"); - assert(data->is_BitData(), "need BitData for checkcast"); - Register mdo = klass_RInfo; + if (op->should_profile()) { + Register mdo = klass_RInfo, recv = k_RInfo; + __ bind(profile_cast_success); __ movoop(mdo, md->constant_encoding()); - Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset())); - int header_bits = DataLayout::flag_mask_to_header_mask(BitData::null_seen_byte_constant()); - __ orl(data_addr, header_bits); - __ jmp(done); - __ bind(profile_done); - } else { - __ jcc(Assembler::equal, done); + __ movptr(recv, Address(value, oopDesc::klass_offset_in_bytes())); + Label update_done; + type_profile_helper(mdo, md, data, recv, &done); + __ jmpb(done); + + __ bind(profile_cast_failure); + __ movoop(mdo, md->constant_encoding()); + Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); + __ subptr(counter_addr, DataLayout::counter_increment); + __ jmp(*stub->entry()); } - __ verify_oop(obj); - if (op->fast_check()) { - // get object classo - // not a safepoint as obj null check happens earlier - if (k->is_loaded()) { -#ifdef _LP64 - __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); -#else - __ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding()); -#endif // _LP64 - } else { - __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); - - } - __ jcc(Assembler::notEqual, *stub->entry()); - __ bind(done); - } else { - // get object class - // not a safepoint as obj null check happens earlier - __ movptr(klass_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); - if (k->is_loaded()) { - // See if we get an immediate positive hit -#ifdef _LP64 - __ cmpptr(k_RInfo, Address(klass_RInfo, k->super_check_offset())); -#else - __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding()); -#endif // _LP64 - if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) { - __ jcc(Assembler::notEqual, *stub->entry()); - } else { - // See if we get an immediate positive hit - __ jcc(Assembler::equal, done); - // check for self -#ifdef _LP64 - __ cmpptr(klass_RInfo, k_RInfo); -#else - __ cmpoop(klass_RInfo, k->constant_encoding()); -#endif // _LP64 - __ jcc(Assembler::equal, done); - - __ push(klass_RInfo); -#ifdef _LP64 - __ push(k_RInfo); -#else - __ pushoop(k->constant_encoding()); -#endif // _LP64 - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); - __ pop(klass_RInfo); - __ pop(klass_RInfo); - // result is a boolean - __ cmpl(klass_RInfo, 0); - __ jcc(Assembler::equal, *stub->entry()); - } - __ bind(done); - } else { - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, &done, stub->entry(), NULL); - // call out-of-line instance of __ check_klass_subtype_slow_path(...): - __ push(klass_RInfo); - __ push(k_RInfo); - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); - __ pop(klass_RInfo); - __ pop(k_RInfo); - // result is a boolean - __ cmpl(k_RInfo, 0); - __ jcc(Assembler::equal, *stub->entry()); - __ bind(done); - } - - } - if (dst != obj) { - __ mov(dst, obj); - } - } else if (code == lir_instanceof) { - Register obj = op->object()->as_register(); - Register k_RInfo = op->tmp1()->as_register(); - Register klass_RInfo = op->tmp2()->as_register(); - Register dst = op->result_opr()->as_register(); - ciKlass* k = op->klass(); - - Label done; - Label zero; - Label one; - if (obj == k_RInfo) { - k_RInfo = klass_RInfo; - klass_RInfo = obj; - } - // patching may screw with our temporaries on sparc, - // so let's do it before loading the class - if (!k->is_loaded()) { - jobject2reg_with_patching(k_RInfo, op->info_for_patch()); - } else { - LP64_ONLY(__ movoop(k_RInfo, k->constant_encoding())); - } - assert(obj != k_RInfo, "must be different"); - - __ verify_oop(obj); - if (op->fast_check()) { - __ cmpptr(obj, (int32_t)NULL_WORD); - __ jcc(Assembler::equal, zero); - // get object class - // not a safepoint as obj null check happens earlier - if (LP64_ONLY(false &&) k->is_loaded()) { - NOT_LP64(__ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding())); - k_RInfo = noreg; - } else { - __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); - - } - __ jcc(Assembler::equal, one); - } else { - // get object class - // not a safepoint as obj null check happens earlier - __ cmpptr(obj, (int32_t)NULL_WORD); - __ jcc(Assembler::equal, zero); - __ movptr(klass_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); - -#ifndef _LP64 - if (k->is_loaded()) { - // See if we get an immediate positive hit - __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding()); - __ jcc(Assembler::equal, one); - if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() == k->super_check_offset()) { - // check for self - __ cmpoop(klass_RInfo, k->constant_encoding()); - __ jcc(Assembler::equal, one); - __ push(klass_RInfo); - __ pushoop(k->constant_encoding()); - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); - __ pop(klass_RInfo); - __ pop(dst); - __ jmp(done); - } - } - else // next block is unconditional if LP64: -#endif // LP64 - { - assert(dst != klass_RInfo && dst != k_RInfo, "need 3 registers"); - - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, dst, &one, &zero, NULL); - // call out-of-line instance of __ check_klass_subtype_slow_path(...): - __ push(klass_RInfo); - __ push(k_RInfo); - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); - __ pop(klass_RInfo); - __ pop(dst); - __ jmp(done); - } - } - __ bind(zero); - __ xorptr(dst, dst); - __ jmp(done); - __ bind(one); - __ movptr(dst, 1); __ bind(done); - } else { - ShouldNotReachHere(); - } + } else + if (code == lir_checkcast) { + Register obj = op->object()->as_register(); + Register dst = op->result_opr()->as_register(); + Label success; + emit_typecheck_helper(op, &success, op->stub()->entry(), &success); + __ bind(success); + if (dst != obj) { + __ mov(dst, obj); + } + } else + if (code == lir_instanceof) { + Register obj = op->object()->as_register(); + Register dst = op->result_opr()->as_register(); + Label success, failure, done; + emit_typecheck_helper(op, &success, &failure, &failure); + __ bind(failure); + __ xorptr(dst, dst); + __ jmpb(done); + __ bind(success); + __ movptr(dst, 1); + __ bind(done); + } else { + ShouldNotReachHere(); + } } @@ -1922,7 +1962,6 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { } } - void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result) { Assembler::Condition acond, ncond; switch (condition) { @@ -2014,11 +2053,11 @@ void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr jint c = right->as_constant_ptr()->as_jint(); switch (code) { case lir_add: { - __ increment(lreg, c); + __ incrementl(lreg, c); break; } case lir_sub: { - __ decrement(lreg, c); + __ decrementl(lreg, c); break; } default: ShouldNotReachHere(); @@ -3253,13 +3292,13 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { // Perform additional virtual call profiling for invokevirtual and // invokeinterface bytecodes if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) && - Tier1ProfileVirtualCalls) { + C1ProfileVirtualCalls) { assert(op->recv()->is_single_cpu(), "recv must be allocated"); Register recv = op->recv()->as_register(); assert_different_registers(mdo, recv); assert(data->is_VirtualCallData(), "need VirtualCallData for virtual calls"); ciKlass* known_klass = op->known_holder(); - if (Tier1OptimizeVirtualCallProfiling && known_klass != NULL) { + if (C1OptimizeVirtualCallProfiling && known_klass != NULL) { // We know the type that will be seen at this call site; we can // statically update the methodDataOop rather than needing to do // dynamic tests on the receiver type @@ -3272,7 +3311,7 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { ciKlass* receiver = vc_data->receiver(i); if (known_klass->equals(receiver)) { Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))); - __ addl(data_addr, DataLayout::counter_increment); + __ addptr(data_addr, DataLayout::counter_increment); return; } } @@ -3288,49 +3327,26 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i))); __ movoop(recv_addr, known_klass->constant_encoding()); Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))); - __ addl(data_addr, DataLayout::counter_increment); + __ addptr(data_addr, DataLayout::counter_increment); return; } } } else { __ movptr(recv, Address(recv, oopDesc::klass_offset_in_bytes())); Label update_done; - uint i; - for (i = 0; i < VirtualCallData::row_limit(); i++) { - Label next_test; - // See if the receiver is receiver[n]. - __ cmpptr(recv, Address(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)))); - __ jcc(Assembler::notEqual, next_test); - Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))); - __ addl(data_addr, DataLayout::counter_increment); - __ jmp(update_done); - __ bind(next_test); - } - - // Didn't find receiver; find next empty slot and fill it in - for (i = 0; i < VirtualCallData::row_limit(); i++) { - Label next_test; - Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i))); - __ cmpptr(recv_addr, (int32_t)NULL_WORD); - __ jcc(Assembler::notEqual, next_test); - __ movptr(recv_addr, recv); - __ movl(Address(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))), DataLayout::counter_increment); - __ jmp(update_done); - __ bind(next_test); - } + type_profile_helper(mdo, md, data, recv, &update_done); // Receiver did not match any saved receiver and there is no empty row for it. // Increment total counter to indicate polymorphic case. - __ addl(counter_addr, DataLayout::counter_increment); + __ addptr(counter_addr, DataLayout::counter_increment); __ bind(update_done); } } else { // Static call - __ addl(counter_addr, DataLayout::counter_increment); + __ addptr(counter_addr, DataLayout::counter_increment); } } - void LIR_Assembler::emit_delay(LIR_OpDelay*) { Unimplemented(); } diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp index 291e2969bd4..f1b0ed88021 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp @@ -42,7 +42,10 @@ // method. Address as_Address(LIR_Address* addr, Register tmp); - + // Record the type of the receiver in ReceiverTypeData + void type_profile_helper(Register mdo, + ciMethodData *md, ciProfileData *data, + Register recv, Label* update_done); public: void store_parameter(Register r, int offset_from_esp_in_words); diff --git a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp index df92163cca4..05df6bda708 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -182,10 +182,22 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o } -void LIRGenerator::increment_counter(address counter, int step) { +LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { + LIR_Opr r; + if (type == T_LONG) { + r = LIR_OprFact::longConst(x); + } else if (type == T_INT) { + r = LIR_OprFact::intConst(x); + } else { + ShouldNotReachHere(); + } + return r; +} + +void LIRGenerator::increment_counter(address counter, BasicType type, int step) { LIR_Opr pointer = new_pointer_register(); __ move(LIR_OprFact::intptrConst(counter), pointer); - LIR_Address* addr = new LIR_Address(pointer, T_INT); + LIR_Address* addr = new LIR_Address(pointer, type); increment_counter(addr, step); } @@ -194,7 +206,6 @@ void LIRGenerator::increment_counter(LIR_Address* addr, int step) { __ add((LIR_Opr)addr, LIR_OprFact::intConst(step), (LIR_Opr)addr); } - void LIRGenerator::cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info) { __ cmp_mem_int(condition, base, disp, c, info); } @@ -1145,10 +1156,10 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) { patching_info = state_for(x, x->state_before()); } obj.load_item(); - LIR_Opr tmp = new_register(objectType); __ instanceof(reg, obj.result(), x->klass(), - tmp, new_register(objectType), LIR_OprFact::illegalOpr, - x->direct_compare(), patching_info); + new_register(objectType), new_register(objectType), + !x->klass()->is_loaded() ? new_register(objectType) : LIR_OprFact::illegalOpr, + x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci()); } @@ -1188,8 +1199,7 @@ void LIRGenerator::do_If(If* x) { // add safepoint before generating condition code so it can be recomputed if (x->is_safepoint()) { // increment backedge counter if needed - increment_backedge_counter(state_for(x, x->state_before())); - + increment_backedge_counter(state_for(x, x->state_before()), x->profiled_bci()); __ safepoint(LIR_OprFact::illegalOpr, state_for(x, x->state_before())); } set_no_result(x); @@ -1197,6 +1207,7 @@ void LIRGenerator::do_If(If* x) { LIR_Opr left = xin->result(); LIR_Opr right = yin->result(); __ cmp(lir_cond(cond), left, right); + // Generate branch profiling. Profiling code doesn't kill flags. profile_branch(x, cond); move_to_phi(x->state()); if (x->x()->type()->is_float_kind()) { diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp index 230c4b28ea3..9c9341038ec 100644 --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -1068,15 +1068,16 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { break; -#ifdef TIERED case counter_overflow_id: { - Register bci = rax; + Register bci = rax, method = rbx; __ enter(); - OopMap* map = save_live_registers(sasm, 2); + OopMap* map = save_live_registers(sasm, 3); // Retrieve bci __ movl(bci, Address(rbp, 2*BytesPerWord)); - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, counter_overflow), bci); + // And a pointer to the methodOop + __ movptr(method, Address(rbp, 3*BytesPerWord)); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, counter_overflow), bci, method); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); restore_live_registers(sasm); @@ -1084,7 +1085,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ ret(0); } break; -#endif // TIERED case new_type_array_id: case new_object_array_id: diff --git a/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp index 7bb089fc3fa..f3700f33c7b 100644 --- a/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,14 +35,7 @@ define_pd_global(bool, ProfileTraps, false); define_pd_global(bool, UseOnStackReplacement, true ); define_pd_global(bool, TieredCompilation, false); define_pd_global(intx, CompileThreshold, 1500 ); -define_pd_global(intx, Tier2CompileThreshold, 1500 ); -define_pd_global(intx, Tier3CompileThreshold, 2500 ); -define_pd_global(intx, Tier4CompileThreshold, 4500 ); - define_pd_global(intx, BackEdgeThreshold, 100000); -define_pd_global(intx, Tier2BackEdgeThreshold, 100000); -define_pd_global(intx, Tier3BackEdgeThreshold, 100000); -define_pd_global(intx, Tier4BackEdgeThreshold, 100000); define_pd_global(intx, OnStackReplacePercentage, 933 ); define_pd_global(intx, FreqInlineSize, 325 ); diff --git a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp index 44accd2a759..ae3029c4064 100644 --- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,19 +39,8 @@ define_pd_global(bool, ProfileInterpreter, false); define_pd_global(bool, ProfileInterpreter, true); #endif // CC_INTERP define_pd_global(bool, TieredCompilation, false); -#ifdef TIERED -define_pd_global(intx, CompileThreshold, 1000); -#else define_pd_global(intx, CompileThreshold, 10000); -#endif // TIERED -define_pd_global(intx, Tier2CompileThreshold, 10000); -define_pd_global(intx, Tier3CompileThreshold, 20000); -define_pd_global(intx, Tier4CompileThreshold, 40000); - define_pd_global(intx, BackEdgeThreshold, 100000); -define_pd_global(intx, Tier2BackEdgeThreshold, 100000); -define_pd_global(intx, Tier3BackEdgeThreshold, 100000); -define_pd_global(intx, Tier4BackEdgeThreshold, 100000); define_pd_global(intx, OnStackReplacePercentage, 140); define_pd_global(intx, ConditionalMoveLimit, 3); diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp index cfc20539783..a41ff1dbe3a 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp @@ -141,12 +141,12 @@ bool frame::safe_for_sender(JavaThread *thread) { } // Could just be some random pointer within the codeBlob - - if (!sender_blob->instructions_contains(sender_pc)) return false; + if (!sender_blob->code_contains(sender_pc)) { + return false; + } // We should never be able to see an adapter if the current frame is something from code cache - - if ( sender_blob->is_adapter_blob()) { + if (sender_blob->is_adapter_blob()) { return false; } @@ -340,7 +340,7 @@ void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool fr._unextended_sp = unextended_sp; address original_pc = nm->get_original_pc(&fr); - assert(nm->code_contains(original_pc), "original PC must be in nmethod"); + assert(nm->insts_contains(original_pc), "original PC must be in nmethod"); assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be"); } #endif diff --git a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp index 8059ed5fe65..0f4881c2b9a 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp @@ -63,7 +63,7 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address address original_pc = nmethod::get_deopt_original_pc(this); if (original_pc != NULL) { _pc = original_pc; - assert(((nmethod*)_cb)->code_contains(_pc), "original PC must be in nmethod"); + assert(((nmethod*)_cb)->insts_contains(_pc), "original PC must be in nmethod"); _deopt_state = is_deoptimized; } else { _deopt_state = not_deoptimized; diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp index aae41ec4c08..013c6c03739 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp @@ -1397,3 +1397,17 @@ void InterpreterMacroAssembler::notify_method_exit( NOT_CC_INTERP(pop(state)); } } + +// Jump if ((*counter_addr += increment) & mask) satisfies the condition. +void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, + int increment, int mask, + Register scratch, bool preloaded, + Condition cond, Label* where) { + if (!preloaded) { + movl(scratch, counter_addr); + } + incrementl(scratch, increment); + movl(counter_addr, scratch); + andl(scratch, mask); + jcc(cond, *where); +} diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp index 97f044c9066..600f0566f7d 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp @@ -185,6 +185,10 @@ class InterpreterMacroAssembler: public MacroAssembler { bool decrement = false); void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); + void increment_mask_and_jump(Address counter_addr, + int increment, int mask, + Register scratch, bool preloaded, + Condition cond, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant); void test_mdp_data_at(Register mdp_in, int offset, Register value, Register test_value_out, diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp index 50b0b4cd88b..6392742aac5 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp @@ -1480,3 +1480,17 @@ void InterpreterMacroAssembler::notify_method_exit( NOT_CC_INTERP(pop(state)); } } + +// Jump if ((*counter_addr += increment) & mask) satisfies the condition. +void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, + int increment, int mask, + Register scratch, bool preloaded, + Condition cond, Label* where) { + if (!preloaded) { + movl(scratch, counter_addr); + } + incrementl(scratch, increment); + movl(counter_addr, scratch); + andl(scratch, mask); + jcc(cond, *where); +} diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp index 8eb9537501a..6f485952580 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp @@ -194,6 +194,10 @@ class InterpreterMacroAssembler: public MacroAssembler { bool decrement = false); void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); + void increment_mask_and_jump(Address counter_addr, + int increment, int mask, + Register scratch, bool preloaded, + Condition cond, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant); void test_mdp_data_at(Register mdp_in, int offset, Register value, Register test_value_out, diff --git a/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp index aa34d50a2da..0a63657dcb4 100644 --- a/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,10 +54,10 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { default: ShouldNotReachHere(); } ResourceMark rm; - BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE*wordSize); - address fast_entry = b->instructions_begin(); - CodeBuffer cbuf(fast_entry, b->instructions_size()); + BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize); + CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); + address fast_entry = __ pc(); Label slow; @@ -135,11 +135,11 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { return fast_entry; #else switch (type) { - case T_BOOLEAN: jni_fast_GetBooleanField_fp = (GetBooleanField_t)fast_entry; break; - case T_BYTE: jni_fast_GetByteField_fp = (GetByteField_t)fast_entry; break; - case T_CHAR: jni_fast_GetCharField_fp = (GetCharField_t)fast_entry; break; - case T_SHORT: jni_fast_GetShortField_fp = (GetShortField_t)fast_entry; break; - case T_INT: jni_fast_GetIntField_fp = (GetIntField_t)fast_entry; + case T_BOOLEAN: jni_fast_GetBooleanField_fp = (GetBooleanField_t) fast_entry; break; + case T_BYTE: jni_fast_GetByteField_fp = (GetByteField_t) fast_entry; break; + case T_CHAR: jni_fast_GetCharField_fp = (GetCharField_t) fast_entry; break; + case T_SHORT: jni_fast_GetShortField_fp = (GetShortField_t) fast_entry; break; + case T_INT: jni_fast_GetIntField_fp = (GetIntField_t) fast_entry; break; } return os::win32::fast_jni_accessor_wrapper(type); #endif @@ -168,10 +168,10 @@ address JNI_FastGetField::generate_fast_get_int_field() { address JNI_FastGetField::generate_fast_get_long_field() { const char *name = "jni_fast_GetLongField"; ResourceMark rm; - BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE*wordSize); - address fast_entry = b->instructions_begin(); - CodeBuffer cbuf(fast_entry, b->instructions_size()); + BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize); + CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); + address fast_entry = __ pc(); Label slow; @@ -246,7 +246,7 @@ address JNI_FastGetField::generate_fast_get_long_field() { #ifndef _WINDOWS return fast_entry; #else - jni_fast_GetLongField_fp = (GetLongField_t)fast_entry; + jni_fast_GetLongField_fp = (GetLongField_t) fast_entry; return os::win32::fast_jni_accessor_wrapper(T_LONG); #endif } @@ -259,10 +259,10 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { default: ShouldNotReachHere(); } ResourceMark rm; - BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE*wordSize); - address fast_entry = b->instructions_begin(); - CodeBuffer cbuf(fast_entry, b->instructions_size()); + BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize); + CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); + address fast_entry = __ pc(); Label slow_with_pop, slow; @@ -348,8 +348,8 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { return fast_entry; #else switch (type) { - case T_FLOAT: jni_fast_GetFloatField_fp = (GetFloatField_t)fast_entry; break; - case T_DOUBLE: jni_fast_GetDoubleField_fp = (GetDoubleField_t)fast_entry; + case T_FLOAT: jni_fast_GetFloatField_fp = (GetFloatField_t) fast_entry; break; + case T_DOUBLE: jni_fast_GetDoubleField_fp = (GetDoubleField_t) fast_entry; break; } return os::win32::fast_jni_accessor_wrapper(type); #endif diff --git a/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp index 02da6a5abcb..f07ae42e1a8 100644 --- a/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,10 +58,10 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { default: ShouldNotReachHere(); } ResourceMark rm; - BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE); - address fast_entry = b->instructions_begin(); - CodeBuffer cbuf(fast_entry, b->instructions_size()); + BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); + CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); + address fast_entry = __ pc(); Label slow; @@ -156,10 +156,10 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { default: ShouldNotReachHere(); } ResourceMark rm; - BufferBlob* b = BufferBlob::create(name, BUFFER_SIZE); - address fast_entry = b->instructions_begin(); - CodeBuffer cbuf(fast_entry, b->instructions_size()); + BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); + CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); + address fast_entry = __ pc(); Label slow; diff --git a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp index ae4f28c006c..e8cd888cd71 100644 --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp @@ -27,6 +27,14 @@ #define __ _masm-> +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm, address interpreted_entry) { // Just before the actual machine code entry point, allocate space @@ -64,6 +72,7 @@ static void verify_argslot(MacroAssembler* _masm, Register argslot_reg, const char* error_message) { // Verify that argslot lies within (rsp, rbp]. Label L_ok, L_bad; + BLOCK_COMMENT("{ verify_argslot"); __ cmpptr(argslot_reg, rbp); __ jccb(Assembler::above, L_bad); __ cmpptr(rsp, argslot_reg); @@ -71,6 +80,7 @@ static void verify_argslot(MacroAssembler* _masm, Register argslot_reg, __ bind(L_bad); __ stop(error_message); __ bind(L_ok); + BLOCK_COMMENT("} verify_argslot"); } #endif @@ -80,16 +90,21 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* // rbx: methodOop // rcx: receiver method handle (must load from sp[MethodTypeForm.vmslots]) // rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) - // rdx: garbage temp, blown away + // rdx, rdi: garbage temp, blown away Register rbx_method = rbx; Register rcx_recv = rcx; Register rax_mtype = rax; Register rdx_temp = rdx; + Register rdi_temp = rdi; // emit WrongMethodType path first, to enable jccb back-branch from main path Label wrong_method_type; __ bind(wrong_method_type); + Label invoke_generic_slow_path; + assert(methodOopDesc::intrinsic_id_size_in_bytes() == sizeof(u1), "");; + __ cmpb(Address(rbx_method, methodOopDesc::intrinsic_id_offset_in_bytes()), (int) vmIntrinsics::_invokeExact); + __ jcc(Assembler::notEqual, invoke_generic_slow_path); __ push(rax_mtype); // required mtype __ push(rcx_recv); // bad mh (1st stacked argument) __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); @@ -106,17 +121,68 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* tem = rax_mtype; // in case there is another indirection } } - Register rbx_temp = rbx_method; // done with incoming methodOop // given the MethodType, find out where the MH argument is buried __ movptr(rdx_temp, Address(rax_mtype, - __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rbx_temp))); - __ movl(rdx_temp, Address(rdx_temp, - __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, rbx_temp))); - __ movptr(rcx_recv, __ argument_address(rdx_temp)); + __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rdi_temp))); + Register rdx_vmslots = rdx_temp; + __ movl(rdx_vmslots, Address(rdx_temp, + __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, rdi_temp))); + __ movptr(rcx_recv, __ argument_address(rdx_vmslots)); - __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type); - __ jump_to_method_handle_entry(rcx_recv, rdx_temp); + trace_method_handle(_masm, "invokeExact"); + + __ check_method_handle_type(rax_mtype, rcx_recv, rdi_temp, wrong_method_type); + __ jump_to_method_handle_entry(rcx_recv, rdi_temp); + + // for invokeGeneric (only), apply argument and result conversions on the fly + __ bind(invoke_generic_slow_path); +#ifdef ASSERT + { Label L; + __ cmpb(Address(rbx_method, methodOopDesc::intrinsic_id_offset_in_bytes()), (int) vmIntrinsics::_invokeGeneric); + __ jcc(Assembler::equal, L); + __ stop("bad methodOop::intrinsic_id"); + __ bind(L); + } +#endif //ASSERT + Register rbx_temp = rbx_method; // don't need it now + + // make room on the stack for another pointer: + Register rcx_argslot = rcx_recv; + __ lea(rcx_argslot, __ argument_address(rdx_vmslots, 1)); + insert_arg_slots(_masm, 2 * stack_move_unit(), _INSERT_REF_MASK, + rcx_argslot, rbx_temp, rdx_temp); + + // load up an adapter from the calling type (Java weaves this) + __ movptr(rdx_temp, Address(rax_mtype, + __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rdi_temp))); + Register rdx_adapter = rdx_temp; + // movptr(rdx_adapter, Address(rdx_temp, java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes())); + // deal with old JDK versions: + __ lea(rdi_temp, Address(rdx_temp, + __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, rdi_temp))); + __ cmpptr(rdi_temp, rdx_temp); + Label sorry_no_invoke_generic; + __ jccb(Assembler::below, sorry_no_invoke_generic); + + __ movptr(rdx_adapter, Address(rdi_temp, 0)); + __ testptr(rdx_adapter, rdx_adapter); + __ jccb(Assembler::zero, sorry_no_invoke_generic); + __ movptr(Address(rcx_argslot, 1 * Interpreter::stackElementSize), rdx_adapter); + // As a trusted first argument, pass the type being called, so the adapter knows + // the actual types of the arguments and return values. + // (Generic invokers are shared among form-families of method-type.) + __ movptr(Address(rcx_argslot, 0 * Interpreter::stackElementSize), rax_mtype); + // FIXME: assert that rdx_adapter is of the right method-type. + __ mov(rcx, rdx_adapter); + trace_method_handle(_masm, "invokeGeneric"); + __ jump_to_method_handle_entry(rcx, rdi_temp); + + __ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available! + __ movptr(rcx_recv, Address(rcx_argslot, -1 * Interpreter::stackElementSize)); // recover original MH + __ push(rax_mtype); // required mtype + __ push(rcx_recv); // bad mh (1st stacked argument) + __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); return entry_point; } @@ -164,11 +230,12 @@ void MethodHandles::insert_arg_slots(MacroAssembler* _masm, // for (rdx = rsp + size; rdx < argslot; rdx++) // rdx[-size] = rdx[0] // argslot -= size; + BLOCK_COMMENT("insert_arg_slots {"); __ mov(rdx_temp, rsp); // source pointer for copy __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr)); { Label loop; - __ bind(loop); + __ BIND(loop); // pull one word down each time through the loop __ movptr(rbx_temp, Address(rdx_temp, 0)); __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); @@ -179,6 +246,7 @@ void MethodHandles::insert_arg_slots(MacroAssembler* _masm, // Now move the argslot down, to point to the opened-up space. __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr)); + BLOCK_COMMENT("} insert_arg_slots"); } // Helper to remove argument slots from the stack. @@ -218,6 +286,7 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm, } #endif + BLOCK_COMMENT("remove_arg_slots {"); // Pull up everything shallower than rax_argslot. // Then remove the excess space on the stack. // The stacked return address gets pulled up with everything else. @@ -229,7 +298,7 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm, __ lea(rdx_temp, Address(rax_argslot, -wordSize)); // source pointer for copy { Label loop; - __ bind(loop); + __ BIND(loop); // pull one word up each time through the loop __ movptr(rbx_temp, Address(rdx_temp, 0)); __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); @@ -242,12 +311,14 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm, __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr)); // And adjust the argslot address to point at the deletion point. __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr)); + BLOCK_COMMENT("} remove_arg_slots"); } #ifndef PRODUCT extern "C" void print_method_handle(oop mh); void trace_method_handle_stub(const char* adaptername, oop mh, + intptr_t* saved_regs, intptr_t* entry_sp, intptr_t* saved_sp, intptr_t* saved_bp) { @@ -256,9 +327,47 @@ void trace_method_handle_stub(const char* adaptername, intptr_t* base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset]; printf("MH %s mh="INTPTR_FORMAT" sp=("INTPTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="INTPTR_FORMAT"\n", adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp); - if (last_sp != saved_sp) + if (last_sp != saved_sp && last_sp != NULL) printf("*** last_sp="INTPTR_FORMAT"\n", (intptr_t)last_sp); - if (Verbose) print_method_handle(mh); + if (Verbose) { + printf(" reg dump: "); + int saved_regs_count = (entry_sp-1) - saved_regs; + // 32 bit: rdi rsi rbp rsp; rbx rdx rcx (*) rax + int i; + for (i = 0; i <= saved_regs_count; i++) { + if (i > 0 && i % 4 == 0 && i != saved_regs_count) + printf("\n + dump: "); + printf(" %d: "INTPTR_FORMAT, i, saved_regs[i]); + } + printf("\n"); + int stack_dump_count = 16; + if (stack_dump_count < (int)(saved_bp + 2 - saved_sp)) + stack_dump_count = (int)(saved_bp + 2 - saved_sp); + if (stack_dump_count > 64) stack_dump_count = 48; + for (i = 0; i < stack_dump_count; i += 4) { + printf(" dump at SP[%d] "INTPTR_FORMAT": "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT"\n", + i, &entry_sp[i+0], entry_sp[i+0], entry_sp[i+1], entry_sp[i+2], entry_sp[i+3]); + } + print_method_handle(mh); + } +} +void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) { + if (!TraceMethodHandles) return; + BLOCK_COMMENT("trace_method_handle {"); + __ push(rax); + __ lea(rax, Address(rsp, wordSize*6)); // entry_sp + __ pusha(); + // arguments: + __ push(rbp); // interpreter frame pointer + __ push(rsi); // saved_sp + __ push(rax); // entry_sp + __ push(rcx); // mh + __ push(rcx); + __ movptr(Address(rsp, 0), (intptr_t) adaptername); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 5); + __ popa(); + __ pop(rax); + BLOCK_COMMENT("} trace_method_handle"); } #endif //PRODUCT @@ -324,21 +433,9 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan address interp_entry = __ pc(); if (UseCompressedOops) __ unimplemented("UseCompressedOops"); -#ifndef PRODUCT - if (TraceMethodHandles) { - __ push(rax); __ push(rbx); __ push(rcx); __ push(rdx); __ push(rsi); __ push(rdi); - __ lea(rax, Address(rsp, wordSize*6)); // entry_sp - // arguments: - __ push(rbp); // interpreter frame pointer - __ push(rsi); // saved_sp - __ push(rax); // entry_sp - __ push(rcx); // mh - __ push(rcx); - __ movptr(Address(rsp, 0), (intptr_t)entry_name(ek)); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 5); - __ pop(rdi); __ pop(rsi); __ pop(rdx); __ pop(rcx); __ pop(rbx); __ pop(rax); - } -#endif //PRODUCT + trace_method_handle(_masm, entry_name(ek)); + + BLOCK_COMMENT(entry_name(ek)); switch ((int) ek) { case _raise_exception: diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp index f6e6fff9d05..9a7c6a022da 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp @@ -1039,6 +1039,33 @@ class StubGenerator: public StubCodeGenerator { } + address generate_fill(BasicType t, bool aligned, const char *name) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + + BLOCK_COMMENT("Entry:"); + + const Register to = rdi; // source array address + const Register value = rdx; // value + const Register count = rsi; // elements count + + __ enter(); // required for proper stackwalking of RuntimeStub frame + __ push(rsi); + __ push(rdi); + __ movptr(to , Address(rsp, 12+ 4)); + __ movl(value, Address(rsp, 12+ 8)); + __ movl(count, Address(rsp, 12+ 12)); + + __ generate_fill(t, aligned, to, value, count, rax, xmm0); + + __ pop(rdi); + __ pop(rsi); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + return start; + } + address generate_conjoint_copy(BasicType t, bool aligned, Address::ScaleFactor sf, address nooverlap_target, @@ -2001,6 +2028,13 @@ class StubGenerator: public StubCodeGenerator { generate_conjoint_long_copy(entry, &entry_jlong_arraycopy, "jlong_arraycopy"); + StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill"); + StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill"); + StubRoutines::_jint_fill = generate_fill(T_INT, false, "jint_fill"); + StubRoutines::_arrayof_jbyte_fill = generate_fill(T_BYTE, true, "arrayof_jbyte_fill"); + StubRoutines::_arrayof_jshort_fill = generate_fill(T_SHORT, true, "arrayof_jshort_fill"); + StubRoutines::_arrayof_jint_fill = generate_fill(T_INT, true, "arrayof_jint_fill"); + StubRoutines::_arrayof_jint_disjoint_arraycopy = StubRoutines::_jint_disjoint_arraycopy; StubRoutines::_arrayof_oop_disjoint_arraycopy = diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 9dacdcaf316..57d3b5147d4 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -1625,6 +1625,26 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_fill(BasicType t, bool aligned, const char *name) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + + BLOCK_COMMENT("Entry:"); + + const Register to = c_rarg0; // source array address + const Register value = c_rarg1; // value + const Register count = c_rarg2; // elements count + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + __ generate_fill(t, aligned, to, value, count, rax, xmm0); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + return start; + } + // Arguments: // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary // ignored @@ -2712,6 +2732,13 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy"); StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy"); + StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill"); + StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill"); + StubRoutines::_jint_fill = generate_fill(T_INT, false, "jint_fill"); + StubRoutines::_arrayof_jbyte_fill = generate_fill(T_BYTE, true, "arrayof_jbyte_fill"); + StubRoutines::_arrayof_jshort_fill = generate_fill(T_SHORT, true, "arrayof_jshort_fill"); + StubRoutines::_arrayof_jint_fill = generate_fill(T_INT, true, "arrayof_jint_fill"); + // We don't generate specialized code for HeapWord-aligned source // arrays, so just use the code we've already generated StubRoutines::_arrayof_jbyte_disjoint_arraycopy = StubRoutines::_jbyte_disjoint_arraycopy; diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp index a338d5fa68d..cfbd52fde9f 100644 --- a/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp +++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp @@ -33,7 +33,7 @@ enum platform_dependent_constants { // MethodHandles adapters enum method_handles_platform_dependent_constants { - method_handles_adapters_code_size = 5000 + method_handles_adapters_code_size = 10000 }; class x86 { diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp index 4b040e5f1a6..393d868d903 100644 --- a/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp +++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp @@ -35,7 +35,7 @@ enum platform_dependent_constants { // MethodHandles adapters enum method_handles_platform_dependent_constants { - method_handles_adapters_code_size = 13000 + method_handles_adapters_code_size = 26000 }; class x86 { diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index c7fbd4b15b4..513263486ec 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -359,40 +359,62 @@ address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, // rcx: invocation counter // void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { + const Address invocation_counter(rbx, in_bytes(methodOopDesc::invocation_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + // Note: In tiered we increment either counters in methodOop or in MDO depending if we're profiling or not. + if (TieredCompilation) { + int increment = InvocationCounter::count_increment; + int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; + Label no_mdo, done; + if (ProfileInterpreter) { + // Are we profiling? + __ movptr(rax, Address(rbx, methodOopDesc::method_data_offset())); + __ testptr(rax, rax); + __ jccb(Assembler::zero, no_mdo); + // Increment counter in the MDO + const Address mdo_invocation_counter(rax, in_bytes(methodDataOopDesc::invocation_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); + __ jmpb(done); + } + __ bind(no_mdo); + // Increment counter in methodOop (we don't need to load it, it's in rcx). + __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, true, Assembler::zero, overflow); + __ bind(done); + } else { + const Address backedge_counter (rbx, methodOopDesc::backedge_counter_offset() + + InvocationCounter::counter_offset()); - const Address invocation_counter(rbx, methodOopDesc::invocation_counter_offset() + InvocationCounter::counter_offset()); - const Address backedge_counter (rbx, methodOopDesc::backedge_counter_offset() + InvocationCounter::counter_offset()); + if (ProfileInterpreter) { // %%% Merge this into methodDataOop + __ incrementl(Address(rbx,methodOopDesc::interpreter_invocation_counter_offset())); + } + // Update standard invocation counters + __ movl(rax, backedge_counter); // load backedge counter - if (ProfileInterpreter) { // %%% Merge this into methodDataOop - __ incrementl(Address(rbx,methodOopDesc::interpreter_invocation_counter_offset())); - } - // Update standard invocation counters - __ movl(rax, backedge_counter); // load backedge counter + __ incrementl(rcx, InvocationCounter::count_increment); + __ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits - __ incrementl(rcx, InvocationCounter::count_increment); - __ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits + __ movl(invocation_counter, rcx); // save invocation count + __ addl(rcx, rax); // add both counters - __ movl(invocation_counter, rcx); // save invocation count - __ addl(rcx, rax); // add both counters + // profile_method is non-null only for interpreted method so + // profile_method != NULL == !native_call + // BytecodeInterpreter only calls for native so code is elided. - // profile_method is non-null only for interpreted method so - // profile_method != NULL == !native_call - // BytecodeInterpreter only calls for native so code is elided. + if (ProfileInterpreter && profile_method != NULL) { + // Test to see if we should create a method data oop + __ cmp32(rcx, + ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); + __ jcc(Assembler::less, *profile_method_continue); + + // if no method data exists, go to profile_method + __ test_method_data_pointer(rax, *profile_method); + } - if (ProfileInterpreter && profile_method != NULL) { - // Test to see if we should create a method data oop __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); - __ jcc(Assembler::less, *profile_method_continue); - - // if no method data exists, go to profile_method - __ test_method_data_pointer(rax, *profile_method); + ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); + __ jcc(Assembler::aboveEqual, *overflow); } - - __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); - __ jcc(Assembler::aboveEqual, *overflow); - } void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 1d4266e4f6a..b39c7f8575d 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -310,42 +310,61 @@ void InterpreterGenerator::generate_counter_incr( Label* overflow, Label* profile_method, Label* profile_method_continue) { - - const Address invocation_counter(rbx, - methodOopDesc::invocation_counter_offset() + + const Address invocation_counter(rbx, in_bytes(methodOopDesc::invocation_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + // Note: In tiered we increment either counters in methodOop or in MDO depending if we're profiling or not. + if (TieredCompilation) { + int increment = InvocationCounter::count_increment; + int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; + Label no_mdo, done; + if (ProfileInterpreter) { + // Are we profiling? + __ movptr(rax, Address(rbx, methodOopDesc::method_data_offset())); + __ testptr(rax, rax); + __ jccb(Assembler::zero, no_mdo); + // Increment counter in the MDO + const Address mdo_invocation_counter(rax, in_bytes(methodDataOopDesc::invocation_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); + __ jmpb(done); + } + __ bind(no_mdo); + // Increment counter in methodOop (we don't need to load it, it's in ecx). + __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, true, Assembler::zero, overflow); + __ bind(done); + } else { + const Address backedge_counter(rbx, + methodOopDesc::backedge_counter_offset() + InvocationCounter::counter_offset()); - const Address backedge_counter(rbx, - methodOopDesc::backedge_counter_offset() + - InvocationCounter::counter_offset()); - if (ProfileInterpreter) { // %%% Merge this into methodDataOop - __ incrementl(Address(rbx, - methodOopDesc::interpreter_invocation_counter_offset())); + if (ProfileInterpreter) { // %%% Merge this into methodDataOop + __ incrementl(Address(rbx, + methodOopDesc::interpreter_invocation_counter_offset())); + } + // Update standard invocation counters + __ movl(rax, backedge_counter); // load backedge counter + + __ incrementl(rcx, InvocationCounter::count_increment); + __ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits + + __ movl(invocation_counter, rcx); // save invocation count + __ addl(rcx, rax); // add both counters + + // profile_method is non-null only for interpreted method so + // profile_method != NULL == !native_call + + if (ProfileInterpreter && profile_method != NULL) { + // Test to see if we should create a method data oop + __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); + __ jcc(Assembler::less, *profile_method_continue); + + // if no method data exists, go to profile_method + __ test_method_data_pointer(rax, *profile_method); + } + + __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); + __ jcc(Assembler::aboveEqual, *overflow); } - // Update standard invocation counters - __ movl(rax, backedge_counter); // load backedge counter - - __ incrementl(rcx, InvocationCounter::count_increment); - __ andl(rax, InvocationCounter::count_mask_value); // mask out the - // status bits - - __ movl(invocation_counter, rcx); // save invocation count - __ addl(rcx, rax); // add both counters - - // profile_method is non-null only for interpreted method so - // profile_method != NULL == !native_call - - if (ProfileInterpreter && profile_method != NULL) { - // Test to see if we should create a method data oop - __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); - __ jcc(Assembler::less, *profile_method_continue); - - // if no method data exists, go to profile_method - __ test_method_data_pointer(rax, *profile_method); - } - - __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); - __ jcc(Assembler::aboveEqual, *overflow); } void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp index b41c646c755..5da242409c0 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -1558,47 +1558,68 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ testl(rdx, rdx); // check if forward or backward branch __ jcc(Assembler::positive, dispatch); // count only if backward branch - // increment counter - __ movl(rax, Address(rcx, be_offset)); // load backedge counter - __ incrementl(rax, InvocationCounter::count_increment); // increment counter - __ movl(Address(rcx, be_offset), rax); // store counter - - __ movl(rax, Address(rcx, inv_offset)); // load invocation counter - __ andl(rax, InvocationCounter::count_mask_value); // and the status bits - __ addl(rax, Address(rcx, be_offset)); // add both counters - - if (ProfileInterpreter) { - // Test to see if we should create a method data oop - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); - __ jcc(Assembler::less, dispatch); - - // if no method data exists, go to profile method - __ test_method_data_pointer(rax, profile_method); - - if (UseOnStackReplacement) { - // check for overflow against rbx, which is the MDO taken count - __ cmp32(rbx, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); - __ jcc(Assembler::below, dispatch); - - // When ProfileInterpreter is on, the backedge_count comes from the - // methodDataOop, which value does not get reset on the call to - // frequency_counter_overflow(). To avoid excessive calls to the overflow - // routine while the method is being compiled, add a second test to make - // sure the overflow function is called only once every overflow_frequency. - const int overflow_frequency = 1024; - __ andptr(rbx, overflow_frequency-1); - __ jcc(Assembler::zero, backedge_counter_overflow); - + if (TieredCompilation) { + Label no_mdo; + int increment = InvocationCounter::count_increment; + int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; + if (ProfileInterpreter) { + // Are we profiling? + __ movptr(rbx, Address(rcx, in_bytes(methodOopDesc::method_data_offset()))); + __ testptr(rbx, rbx); + __ jccb(Assembler::zero, no_mdo); + // Increment the MDO backedge counter + const Address mdo_backedge_counter(rbx, in_bytes(methodDataOopDesc::backedge_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, + rax, false, Assembler::zero, &backedge_counter_overflow); + __ jmp(dispatch); } + __ bind(no_mdo); + // Increment backedge counter in methodOop + __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, + rax, false, Assembler::zero, &backedge_counter_overflow); } else { - if (UseOnStackReplacement) { - // check for overflow against rax, which is the sum of the counters - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); - __ jcc(Assembler::aboveEqual, backedge_counter_overflow); + // increment counter + __ movl(rax, Address(rcx, be_offset)); // load backedge counter + __ incrementl(rax, InvocationCounter::count_increment); // increment counter + __ movl(Address(rcx, be_offset), rax); // store counter + __ movl(rax, Address(rcx, inv_offset)); // load invocation counter + __ andl(rax, InvocationCounter::count_mask_value); // and the status bits + __ addl(rax, Address(rcx, be_offset)); // add both counters + + if (ProfileInterpreter) { + // Test to see if we should create a method data oop + __ cmp32(rax, + ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); + __ jcc(Assembler::less, dispatch); + + // if no method data exists, go to profile method + __ test_method_data_pointer(rax, profile_method); + + if (UseOnStackReplacement) { + // check for overflow against rbx, which is the MDO taken count + __ cmp32(rbx, + ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ jcc(Assembler::below, dispatch); + + // When ProfileInterpreter is on, the backedge_count comes from the + // methodDataOop, which value does not get reset on the call to + // frequency_counter_overflow(). To avoid excessive calls to the overflow + // routine while the method is being compiled, add a second test to make + // sure the overflow function is called only once every overflow_frequency. + const int overflow_frequency = 1024; + __ andptr(rbx, overflow_frequency-1); + __ jcc(Assembler::zero, backedge_counter_overflow); + } + } else { + if (UseOnStackReplacement) { + // check for overflow against rax, which is the sum of the counters + __ cmp32(rax, + ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ jcc(Assembler::aboveEqual, backedge_counter_overflow); + + } } } __ bind(dispatch); diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp index 832e96bd458..4f46e9f800d 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -1583,51 +1583,71 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // r14: locals pointer __ testl(rdx, rdx); // check if forward or backward branch __ jcc(Assembler::positive, dispatch); // count only if backward branch - - // increment counter - __ movl(rax, Address(rcx, be_offset)); // load backedge counter - __ incrementl(rax, InvocationCounter::count_increment); // increment - // counter - __ movl(Address(rcx, be_offset), rax); // store counter - - __ movl(rax, Address(rcx, inv_offset)); // load invocation counter - __ andl(rax, InvocationCounter::count_mask_value); // and the status bits - __ addl(rax, Address(rcx, be_offset)); // add both counters - - if (ProfileInterpreter) { - // Test to see if we should create a method data oop - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); - __ jcc(Assembler::less, dispatch); - - // if no method data exists, go to profile method - __ test_method_data_pointer(rax, profile_method); - - if (UseOnStackReplacement) { - // check for overflow against ebx which is the MDO taken count - __ cmp32(rbx, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); - __ jcc(Assembler::below, dispatch); - - // When ProfileInterpreter is on, the backedge_count comes - // from the methodDataOop, which value does not get reset on - // the call to frequency_counter_overflow(). To avoid - // excessive calls to the overflow routine while the method is - // being compiled, add a second test to make sure the overflow - // function is called only once every overflow_frequency. - const int overflow_frequency = 1024; - __ andl(rbx, overflow_frequency - 1); - __ jcc(Assembler::zero, backedge_counter_overflow); - + if (TieredCompilation) { + Label no_mdo; + int increment = InvocationCounter::count_increment; + int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; + if (ProfileInterpreter) { + // Are we profiling? + __ movptr(rbx, Address(rcx, in_bytes(methodOopDesc::method_data_offset()))); + __ testptr(rbx, rbx); + __ jccb(Assembler::zero, no_mdo); + // Increment the MDO backedge counter + const Address mdo_backedge_counter(rbx, in_bytes(methodDataOopDesc::backedge_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, + rax, false, Assembler::zero, &backedge_counter_overflow); + __ jmp(dispatch); } + __ bind(no_mdo); + // Increment backedge counter in methodOop + __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, + rax, false, Assembler::zero, &backedge_counter_overflow); } else { - if (UseOnStackReplacement) { - // check for overflow against eax, which is the sum of the - // counters - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); - __ jcc(Assembler::aboveEqual, backedge_counter_overflow); + // increment counter + __ movl(rax, Address(rcx, be_offset)); // load backedge counter + __ incrementl(rax, InvocationCounter::count_increment); // increment counter + __ movl(Address(rcx, be_offset), rax); // store counter + __ movl(rax, Address(rcx, inv_offset)); // load invocation counter + __ andl(rax, InvocationCounter::count_mask_value); // and the status bits + __ addl(rax, Address(rcx, be_offset)); // add both counters + + if (ProfileInterpreter) { + // Test to see if we should create a method data oop + __ cmp32(rax, + ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); + __ jcc(Assembler::less, dispatch); + + // if no method data exists, go to profile method + __ test_method_data_pointer(rax, profile_method); + + if (UseOnStackReplacement) { + // check for overflow against ebx which is the MDO taken count + __ cmp32(rbx, + ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ jcc(Assembler::below, dispatch); + + // When ProfileInterpreter is on, the backedge_count comes + // from the methodDataOop, which value does not get reset on + // the call to frequency_counter_overflow(). To avoid + // excessive calls to the overflow routine while the method is + // being compiled, add a second test to make sure the overflow + // function is called only once every overflow_frequency. + const int overflow_frequency = 1024; + __ andl(rbx, overflow_frequency - 1); + __ jcc(Assembler::zero, backedge_counter_overflow); + + } + } else { + if (UseOnStackReplacement) { + // check for overflow against eax, which is the sum of the + // counters + __ cmp32(rax, + ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ jcc(Assembler::aboveEqual, backedge_counter_overflow); + + } } } __ bind(dispatch); @@ -2912,7 +2932,8 @@ void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) void TemplateTable::invokevirtual_helper(Register index, Register recv, Register flags) { - // Uses temporary registers rax, rdx assert_different_registers(index, recv, rax, rdx); + // Uses temporary registers rax, rdx + assert_different_registers(index, recv, rax, rdx); // Test for an invoke of a final method Label notFinal; diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index d6968a4f802..887e71b79e7 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -482,6 +482,15 @@ void VM_Version::get_processor_features() { } } +#ifdef COMPILER2 + if (UseFPUForSpilling) { + if (UseSSE < 2) { + // Only supported with SSE2+ + FLAG_SET_DEFAULT(UseFPUForSpilling, false); + } + } +#endif + assert(0 <= ReadPrefetchInstr && ReadPrefetchInstr <= 3, "invalid value"); assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value"); @@ -520,6 +529,11 @@ void VM_Version::get_processor_features() { if( supports_sse4_2() && supports_ht() ) { // Nehalem based cpus AllocatePrefetchDistance = 192; AllocatePrefetchLines = 4; +#ifdef COMPILER2 + if (AggressiveOpts && FLAG_IS_DEFAULT(UseFPUForSpilling)) { + FLAG_SET_DEFAULT(UseFPUForSpilling, true); + } +#endif } } assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value"); @@ -581,8 +595,7 @@ void VM_Version::initialize() { if (stub_blob == NULL) { vm_exit_during_initialization("Unable to allocate getPsrInfo_stub"); } - CodeBuffer c(stub_blob->instructions_begin(), - stub_blob->instructions_size()); + CodeBuffer c(stub_blob); VM_Version_StubGenerator g(&c); getPsrInfo_stub = CAST_TO_FN_PTR(getPsrInfo_stub_t, g.generate_getPsrInfo()); diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index 80a3b3356b1..5cbfda1bc62 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -296,14 +296,14 @@ protected: result |= CPU_CX8; if (_cpuid_info.std_cpuid1_edx.bits.cmov != 0) result |= CPU_CMOV; - if (_cpuid_info.std_cpuid1_edx.bits.fxsr != 0 || is_amd() && - _cpuid_info.ext_cpuid1_edx.bits.fxsr != 0) + if (_cpuid_info.std_cpuid1_edx.bits.fxsr != 0 || (is_amd() && + _cpuid_info.ext_cpuid1_edx.bits.fxsr != 0)) result |= CPU_FXSR; // HT flag is set for multi-core processors also. if (threads_per_core() > 1) result |= CPU_HT; - if (_cpuid_info.std_cpuid1_edx.bits.mmx != 0 || is_amd() && - _cpuid_info.ext_cpuid1_edx.bits.mmx != 0) + if (_cpuid_info.std_cpuid1_edx.bits.mmx != 0 || (is_amd() && + _cpuid_info.ext_cpuid1_edx.bits.mmx != 0)) result |= CPU_MMX; if (_cpuid_info.std_cpuid1_edx.bits.sse != 0) result |= CPU_SSE; diff --git a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp index 05457687e86..6a27f4fdeef 100644 --- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -209,7 +209,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { (UseCompressedOops ? 16 : 0); // 1 leaq can be 3 bytes + 1 long } else { // Itable stub size - return (DebugVtables ? 512 : 72) + (CountCompiledCalls ? 13 : 0) + + return (DebugVtables ? 512 : 74) + (CountCompiledCalls ? 13 : 0) + (UseCompressedOops ? 32 : 0); // 2 leaqs } // In order to tune these parameters, run the JVM with VM options diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index b4c57056f45..b2efb1099b2 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -350,54 +350,46 @@ void MachBreakpointNode::format( PhaseRegAlloc *, outputStream* st ) const { // EMIT_RM() void emit_rm(CodeBuffer &cbuf, int f1, int f2, int f3) { unsigned char c = (unsigned char)((f1 << 6) | (f2 << 3) | f3); - *(cbuf.code_end()) = c; - cbuf.set_code_end(cbuf.code_end() + 1); + cbuf.insts()->emit_int8(c); } // EMIT_CC() void emit_cc(CodeBuffer &cbuf, int f1, int f2) { unsigned char c = (unsigned char)( f1 | f2 ); - *(cbuf.code_end()) = c; - cbuf.set_code_end(cbuf.code_end() + 1); + cbuf.insts()->emit_int8(c); } // EMIT_OPCODE() void emit_opcode(CodeBuffer &cbuf, int code) { - *(cbuf.code_end()) = (unsigned char)code; - cbuf.set_code_end(cbuf.code_end() + 1); + cbuf.insts()->emit_int8((unsigned char) code); } // EMIT_OPCODE() w/ relocation information void emit_opcode(CodeBuffer &cbuf, int code, relocInfo::relocType reloc, int offset = 0) { - cbuf.relocate(cbuf.inst_mark() + offset, reloc); + cbuf.relocate(cbuf.insts_mark() + offset, reloc); emit_opcode(cbuf, code); } // EMIT_D8() void emit_d8(CodeBuffer &cbuf, int d8) { - *(cbuf.code_end()) = (unsigned char)d8; - cbuf.set_code_end(cbuf.code_end() + 1); + cbuf.insts()->emit_int8((unsigned char) d8); } // EMIT_D16() void emit_d16(CodeBuffer &cbuf, int d16) { - *((short *)(cbuf.code_end())) = d16; - cbuf.set_code_end(cbuf.code_end() + 2); + cbuf.insts()->emit_int16(d16); } // EMIT_D32() void emit_d32(CodeBuffer &cbuf, int d32) { - *((int *)(cbuf.code_end())) = d32; - cbuf.set_code_end(cbuf.code_end() + 4); + cbuf.insts()->emit_int32(d32); } // emit 32 bit value and construct relocation entry from relocInfo::relocType void emit_d32_reloc(CodeBuffer &cbuf, int d32, relocInfo::relocType reloc, int format) { - cbuf.relocate(cbuf.inst_mark(), reloc, format); - - *((int *)(cbuf.code_end())) = d32; - cbuf.set_code_end(cbuf.code_end() + 4); + cbuf.relocate(cbuf.insts_mark(), reloc, format); + cbuf.insts()->emit_int32(d32); } // emit 32 bit value and construct relocation entry from RelocationHolder @@ -408,10 +400,8 @@ void emit_d32_reloc(CodeBuffer &cbuf, int d32, RelocationHolder const& rspec, assert(oop(d32)->is_oop() && (ScavengeRootsInCode || !oop(d32)->is_scavengable()), "cannot embed scavengable oops in code"); } #endif - cbuf.relocate(cbuf.inst_mark(), rspec, format); - - *((int *)(cbuf.code_end())) = d32; - cbuf.set_code_end(cbuf.code_end() + 4); + cbuf.relocate(cbuf.insts_mark(), rspec, format); + cbuf.insts()->emit_int32(d32); } // Access stack slot for load or store @@ -613,7 +603,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { emit_rm(cbuf, 0x3, 0x05, ESP_enc); emit_d32(cbuf, framesize); } - C->set_frame_complete(cbuf.code_end() - cbuf.code_begin()); + C->set_frame_complete(cbuf.insts_size()); #ifdef ASSERT if (VerifyStackAtCalls) { @@ -695,7 +685,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { emit_opcode(cbuf, 0x58 | EBP_enc); if( do_polling() && C->is_method_compilation() ) { - cbuf.relocate(cbuf.code_end(), relocInfo::poll_return_type, 0); + cbuf.relocate(cbuf.insts_end(), relocInfo::poll_return_type, 0); emit_opcode(cbuf,0x85); emit_rm(cbuf, 0x0, EAX_enc, 0x5); // EAX emit_d32(cbuf, (intptr_t)os::get_polling_page()); @@ -852,6 +842,39 @@ static int impl_movx_helper( CodeBuffer *cbuf, bool do_size, int src_lo, int dst } } +static int impl_movgpr2x_helper( CodeBuffer *cbuf, bool do_size, int src_lo, int dst_lo, + int src_hi, int dst_hi, int size, outputStream* st ) { + // 32-bit + if (cbuf) { + emit_opcode(*cbuf, 0x66); + emit_opcode(*cbuf, 0x0F); + emit_opcode(*cbuf, 0x6E); + emit_rm(*cbuf, 0x3, Matcher::_regEncode[dst_lo] & 7, Matcher::_regEncode[src_lo] & 7); +#ifndef PRODUCT + } else if (!do_size) { + st->print("movdl %s, %s\t# spill", Matcher::regName[dst_lo], Matcher::regName[src_lo]); +#endif + } + return 4; +} + + +static int impl_movx2gpr_helper( CodeBuffer *cbuf, bool do_size, int src_lo, int dst_lo, + int src_hi, int dst_hi, int size, outputStream* st ) { + // 32-bit + if (cbuf) { + emit_opcode(*cbuf, 0x66); + emit_opcode(*cbuf, 0x0F); + emit_opcode(*cbuf, 0x7E); + emit_rm(*cbuf, 0x3, Matcher::_regEncode[src_lo] & 7, Matcher::_regEncode[dst_lo] & 7); +#ifndef PRODUCT + } else if (!do_size) { + st->print("movdl %s, %s\t# spill", Matcher::regName[dst_lo], Matcher::regName[src_lo]); +#endif + } + return 4; +} + static int impl_mov_helper( CodeBuffer *cbuf, bool do_size, int src, int dst, int size, outputStream* st ) { if( cbuf ) { emit_opcode(*cbuf, 0x8B ); @@ -947,6 +970,12 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, PhaseRegAlloc *ra_, bo 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, st); + // Check for integer reg-xmm reg copy + if( src_first_rc == rc_int && dst_first_rc == rc_xmm ) { + assert( (src_second_rc == rc_bad && dst_second_rc == rc_bad), + "no 64 bit integer-float reg moves" ); + return impl_movgpr2x_helper(cbuf,do_size,src_first,dst_first,src_second, dst_second, size, st); + } // -------------------------------------- // Check for float reg-reg copy if( src_first_rc == rc_float && dst_first_rc == rc_float ) { @@ -1018,6 +1047,13 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, PhaseRegAlloc *ra_, bo return impl_movx_helper(cbuf,do_size,src_first,dst_first,src_second, dst_second, size, st); } + // Check for xmm reg-integer reg copy + if( src_first_rc == rc_xmm && dst_first_rc == rc_int ) { + assert( (src_second_rc == rc_bad && dst_second_rc == rc_bad), + "no 64 bit float-integer reg moves" ); + return impl_movx2gpr_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, st); @@ -1165,9 +1201,9 @@ void emit_java_to_interp(CodeBuffer &cbuf ) { // mov rbx,0 // jmp -1 - address mark = cbuf.inst_mark(); // get mark within main instrs section + address mark = cbuf.insts_mark(); // get mark within main instrs section - // Note that the code buffer's inst_mark is always relative to insts. + // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a stub. MacroAssembler _masm(&cbuf); @@ -1182,7 +1218,7 @@ void emit_java_to_interp(CodeBuffer &cbuf ) { __ jump(RuntimeAddress(__ pc())); __ end_a_stub(); - // Update current stubs pointer and restore code_end. + // Update current stubs pointer and restore insts_end. } // size of call stub, compiled java to interpretor uint size_java_to_interp() { @@ -1208,7 +1244,7 @@ void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream* st ) const { void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { MacroAssembler masm(&cbuf); #ifdef ASSERT - uint code_size = cbuf.code_size(); + uint insts_size = cbuf.insts_size(); #endif masm.cmpptr(rax, Address(rcx, oopDesc::klass_offset_in_bytes())); masm.jump_cc(Assembler::notEqual, @@ -1220,7 +1256,7 @@ void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { nops_cnt += 1; masm.nop(nops_cnt); - assert(cbuf.code_size() - code_size == size(ra_), "checking code size of inline cache node"); + assert(cbuf.insts_size() - insts_size == size(ra_), "checking code size of inline cache node"); } uint MachUEPNode::size(PhaseRegAlloc *ra_) const { @@ -1242,14 +1278,14 @@ uint size_exception_handler() { // and call a VM stub routine. int emit_exception_handler(CodeBuffer& cbuf) { - // Note that the code buffer's inst_mark is always relative to insts. + // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a handler. MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); if (base == NULL) return 0; // CodeBuffer::expand failed int offset = __ offset(); - __ jump(RuntimeAddress(OptoRuntime::exception_blob()->instructions_begin())); + __ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); __ end_a_stub(); return offset; @@ -1267,7 +1303,7 @@ uint size_deopt_handler() { // Emit deopt handler code. int emit_deopt_handler(CodeBuffer& cbuf) { - // Note that the code buffer's inst_mark is always relative to insts. + // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a handler. MacroAssembler _masm(&cbuf); address base = @@ -1682,12 +1718,12 @@ encode %{ enc_class Lbl (label labl) %{ // JMP, CALL Label *l = $labl$$label; - emit_d32(cbuf, l ? (l->loc_pos() - (cbuf.code_size()+4)) : 0); + emit_d32(cbuf, l ? (l->loc_pos() - (cbuf.insts_size()+4)) : 0); %} enc_class LblShort (label labl) %{ // JMP, CALL Label *l = $labl$$label; - int disp = l ? (l->loc_pos() - (cbuf.code_size()+1)) : 0; + int disp = l ? (l->loc_pos() - (cbuf.insts_size()+1)) : 0; assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp"); emit_d8(cbuf, disp); %} @@ -1718,13 +1754,13 @@ encode %{ Label *l = $labl$$label; $$$emit8$primary; emit_cc(cbuf, $secondary, $cop$$cmpcode); - emit_d32(cbuf, l ? (l->loc_pos() - (cbuf.code_size()+4)) : 0); + emit_d32(cbuf, l ? (l->loc_pos() - (cbuf.insts_size()+4)) : 0); %} enc_class JccShort (cmpOp cop, label labl) %{ // JCC Label *l = $labl$$label; emit_cc(cbuf, $primary, $cop$$cmpcode); - int disp = l ? (l->loc_pos() - (cbuf.code_size()+1)) : 0; + int disp = l ? (l->loc_pos() - (cbuf.insts_size()+1)) : 0; assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp"); emit_d8(cbuf, disp); %} @@ -1792,10 +1828,10 @@ encode %{ enc_class Java_To_Runtime (method meth) %{ // CALL Java_To_Runtime, Java_To_Runtime_Leaf // This is the instruction starting address for relocation info. - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); $$$emit8$primary; // CALL directly to the runtime - emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4), + emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), runtime_call_Relocation::spec(), RELOC_IMM32 ); if (UseSSE >= 2) { @@ -1825,12 +1861,12 @@ encode %{ enc_class pre_call_FPU %{ // If method sets FPU control word restore it here - debug_only(int off0 = cbuf.code_size()); + debug_only(int off0 = cbuf.insts_size()); if( Compile::current()->in_24_bit_fp_mode() ) { MacroAssembler masm(&cbuf); masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std())); } - debug_only(int off1 = cbuf.code_size()); + debug_only(int off1 = cbuf.insts_size()); assert(off1 - off0 == pre_call_FPU_size(), "correct size prediction"); %} @@ -1843,12 +1879,12 @@ encode %{ %} enc_class preserve_SP %{ - debug_only(int off0 = cbuf.code_size()); + debug_only(int off0 = cbuf.insts_size()); MacroAssembler _masm(&cbuf); // RBP is preserved across all calls, even compiled calls. // Use it to preserve RSP in places where the callee might change the SP. __ movptr(rbp_mh_SP_save, rsp); - debug_only(int off1 = cbuf.code_size()); + debug_only(int off1 = cbuf.insts_size()); assert(off1 - off0 == preserve_SP_size(), "correct size prediction"); %} @@ -1860,16 +1896,16 @@ encode %{ enc_class Java_Static_Call (method meth) %{ // JAVA STATIC CALL // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine // who we intended to call. - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); $$$emit8$primary; if ( !_method ) { - emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4), + emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), runtime_call_Relocation::spec(), RELOC_IMM32 ); } else if(_optimized_virtual) { - emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4), + emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), opt_virtual_call_Relocation::spec(), RELOC_IMM32 ); } else { - emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4), + emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), static_call_Relocation::spec(), RELOC_IMM32 ); } if( _method ) { // Emit stub for static call @@ -1881,15 +1917,15 @@ encode %{ // !!!!! // Generate "Mov EAX,0x00", placeholder instruction to load oop-info // emit_call_dynamic_prologue( cbuf ); - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, 0xB8 + EAX_enc); // mov EAX,-1 emit_d32_reloc(cbuf, (int)Universe::non_oop_word(), oop_Relocation::spec_for_immediate(), RELOC_IMM32); - address virtual_call_oop_addr = cbuf.inst_mark(); + address virtual_call_oop_addr = cbuf.insts_mark(); // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine // who we intended to call. - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); $$$emit8$primary; - emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4), + emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), virtual_call_Relocation::spec(virtual_call_oop_addr), RELOC_IMM32 ); %} @@ -1898,7 +1934,7 @@ encode %{ assert( -128 <= disp && disp <= 127, "compiled_code_offset isn't small"); // CALL *[EAX+in_bytes(methodOopDesc::from_compiled_code_entry_point_offset())] - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); $$$emit8$primary; emit_rm(cbuf, 0x01, $secondary, EAX_enc ); // R/M byte emit_d8(cbuf, disp); // Displacement @@ -1930,9 +1966,9 @@ encode %{ // emit_rm(cbuf, 0x3, EBP_enc, EBP_enc); // // // CALL to interpreter. -// cbuf.set_inst_mark(); +// cbuf.set_insts_mark(); // $$$emit8$primary; -// emit_d32_reloc(cbuf, ($labl$$label - (int)(cbuf.code_end()) - 4), +// emit_d32_reloc(cbuf, ($labl$$label - (int)(cbuf.insts_end()) - 4), // runtime_call_Relocation::spec(), RELOC_IMM32 ); // %} @@ -2041,7 +2077,7 @@ encode %{ %} enc_class Opc_MemImm_F(immF src) %{ - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); $$$emit8$primary; emit_rm(cbuf, 0x0, $secondary, 0x5); emit_float_constant(cbuf, $src$$constant); @@ -2234,7 +2270,7 @@ encode %{ %} enc_class set_instruction_start( ) %{ - cbuf.set_inst_mark(); // Mark start of opcode for reloc info in mem operand + cbuf.set_insts_mark(); // Mark start of opcode for reloc info in mem operand %} enc_class RegMem (eRegI ereg, memory mem) %{ // emit_reg_mem @@ -2383,7 +2419,7 @@ encode %{ emit_opcode( cbuf, 0xD9 ); // FLD (i.e., push it) emit_d8( cbuf, 0xC0-1+$src$$reg ); } - cbuf.set_inst_mark(); // Mark start of opcode for reloc info in mem operand + cbuf.set_insts_mark(); // Mark start of opcode for reloc info in mem operand emit_opcode(cbuf,$primary); encode_RegMem(cbuf, reg_encoding, base, index, scale, displace, disp_is_oop); %} @@ -2428,7 +2464,7 @@ encode %{ emit_opcode(cbuf,0x1B); emit_rm(cbuf, 0x3, tmpReg, tmpReg); // AND $tmp,$y - cbuf.set_inst_mark(); // Mark start of opcode for reloc info in mem operand + cbuf.set_insts_mark(); // Mark start of opcode for reloc info in mem operand emit_opcode(cbuf,0x23); int reg_encoding = tmpReg; int base = $mem$$base; @@ -3111,9 +3147,9 @@ encode %{ // PUSH src2.lo emit_opcode(cbuf, 0x50+$src2$$reg ); // CALL directly to the runtime - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf,0xE8); // Call into runtime - emit_d32_reloc(cbuf, (CAST_FROM_FN_PTR(address, SharedRuntime::ldiv) - cbuf.code_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); + emit_d32_reloc(cbuf, (CAST_FROM_FN_PTR(address, SharedRuntime::ldiv) - cbuf.insts_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); // Restore stack emit_opcode(cbuf, 0x83); // add SP, #framesize emit_rm(cbuf, 0x3, 0x00, ESP_enc); @@ -3130,9 +3166,9 @@ encode %{ // PUSH src2.lo emit_opcode(cbuf, 0x50+$src2$$reg ); // CALL directly to the runtime - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf,0xE8); // Call into runtime - emit_d32_reloc(cbuf, (CAST_FROM_FN_PTR(address, SharedRuntime::lrem ) - cbuf.code_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); + emit_d32_reloc(cbuf, (CAST_FROM_FN_PTR(address, SharedRuntime::lrem ) - cbuf.insts_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); // Restore stack emit_opcode(cbuf, 0x83); // add SP, #framesize emit_rm(cbuf, 0x3, 0x00, ESP_enc); @@ -3778,9 +3814,9 @@ encode %{ %} enc_class enc_rethrow() %{ - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, 0xE9); // jmp entry - emit_d32_reloc(cbuf, (int)OptoRuntime::rethrow_stub() - ((int)cbuf.code_end())-4, + emit_d32_reloc(cbuf, (int)OptoRuntime::rethrow_stub() - ((int)cbuf.insts_end())-4, runtime_call_Relocation::spec(), RELOC_IMM32 ); %} @@ -3827,9 +3863,9 @@ encode %{ emit_opcode(cbuf,0xD9 ); // FLD ST(i) emit_d8 (cbuf,0xC0-1+$src$$reg ); // CALL directly to the runtime - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf,0xE8); // Call into runtime - emit_d32_reloc(cbuf, (StubRoutines::d2i_wrapper() - cbuf.code_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); + emit_d32_reloc(cbuf, (StubRoutines::d2i_wrapper() - cbuf.insts_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); // Carry on here... %} @@ -3869,9 +3905,9 @@ encode %{ emit_opcode(cbuf,0xD9 ); // FLD ST(i) emit_d8 (cbuf,0xC0-1+$src$$reg ); // CALL directly to the runtime - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf,0xE8); // Call into runtime - emit_d32_reloc(cbuf, (StubRoutines::d2l_wrapper() - cbuf.code_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); + emit_d32_reloc(cbuf, (StubRoutines::d2l_wrapper() - cbuf.insts_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); // Carry on here... %} @@ -3942,9 +3978,9 @@ encode %{ emit_d8(cbuf,0x04); // CALL directly to the runtime - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf,0xE8); // Call into runtime - emit_d32_reloc(cbuf, (StubRoutines::d2l_wrapper() - cbuf.code_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); + emit_d32_reloc(cbuf, (StubRoutines::d2l_wrapper() - cbuf.insts_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); // Carry on here... %} @@ -4016,9 +4052,9 @@ encode %{ emit_d8(cbuf,0x08); // CALL directly to the runtime - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf,0xE8); // Call into runtime - emit_d32_reloc(cbuf, (StubRoutines::d2l_wrapper() - cbuf.code_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); + emit_d32_reloc(cbuf, (StubRoutines::d2l_wrapper() - cbuf.insts_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); // Carry on here... %} @@ -4076,9 +4112,9 @@ encode %{ emit_d8(cbuf, $primary ? 0x8 : 0x4); // CALL directly to the runtime - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf,0xE8); // Call into runtime - emit_d32_reloc(cbuf, (StubRoutines::d2i_wrapper() - cbuf.code_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); + emit_d32_reloc(cbuf, (StubRoutines::d2i_wrapper() - cbuf.insts_end()) - 4, runtime_call_Relocation::spec(), RELOC_IMM32 ); // Carry on here... %} @@ -4275,7 +4311,7 @@ encode %{ // so the memory operand is used twice in the encoding. enc_class enc_storeL_volatile( memory mem, stackSlotL src ) %{ store_to_stackslot( cbuf, 0x0DF, 0x05, $src$$disp ); - cbuf.set_inst_mark(); // Mark start of FIST in case $mem has an oop + cbuf.set_insts_mark(); // Mark start of FIST in case $mem has an oop emit_opcode(cbuf,0xDF); int rm_byte_opcode = 0x07; int base = $mem$$base; @@ -4299,7 +4335,7 @@ encode %{ bool disp_is_oop = $src->disp_is_oop(); // disp-as-oop when working with static globals encode_RegMem(cbuf, $tmp$$reg, base, index, scale, displace, disp_is_oop); } - cbuf.set_inst_mark(); // Mark start of MOVSD in case $mem has an oop + cbuf.set_insts_mark(); // Mark start of MOVSD in case $mem has an oop { // MOVSD $mem,$tmp ! atomic long store emit_opcode(cbuf,0xF2); emit_opcode(cbuf,0x0F); @@ -4332,7 +4368,7 @@ encode %{ emit_opcode(cbuf,0x62); emit_rm(cbuf, 0x3, $tmp$$reg, $tmp2$$reg); } - cbuf.set_inst_mark(); // Mark start of MOVSD in case $mem has an oop + cbuf.set_insts_mark(); // Mark start of MOVSD in case $mem has an oop { // MOVSD $mem,$tmp ! atomic long store emit_opcode(cbuf,0xF2); emit_opcode(cbuf,0x0F); @@ -4353,7 +4389,7 @@ encode %{ // A better choice might be TESTB [spp + pagesize() - CacheLineSize()],0 enc_class Safepoint_Poll() %{ - cbuf.relocate(cbuf.inst_mark(), relocInfo::poll_type, 0); + cbuf.relocate(cbuf.insts_mark(), relocInfo::poll_type, 0); emit_opcode(cbuf,0x85); emit_rm (cbuf, 0x0, 0x7, 0x5); emit_d32(cbuf, (intptr_t)os::get_polling_page()); @@ -12886,7 +12922,7 @@ instruct jmpConUCF2(cmpOpUCF2 cop, eFlagsRegUCF cmp, label labl) %{ 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; + parity_disp = l ? (l->loc_pos() - (cbuf.insts_size() + 4)) : 0; } else if ($cop$$cmpcode == Assembler::equal) { parity_disp = 6; ok = true; @@ -12896,7 +12932,7 @@ instruct jmpConUCF2(cmpOpUCF2 cop, eFlagsRegUCF cmp, label labl) %{ emit_d32(cbuf, parity_disp); $$$emit8$primary; emit_cc(cbuf, $secondary, $cop$$cmpcode); - int disp = l ? (l->loc_pos() - (cbuf.code_size() + 4)) : 0; + int disp = l ? (l->loc_pos() - (cbuf.insts_size() + 4)) : 0; emit_d32(cbuf, disp); %} ins_pipe(pipe_jcc); @@ -13082,7 +13118,7 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, eFlagsRegUCF cmp, label labl) %{ 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; + parity_disp = l ? (l->loc_pos() - (cbuf.insts_size() + 1)) : 0; } else if ($cop$$cmpcode == Assembler::equal) { parity_disp = 2; } else { @@ -13090,7 +13126,7 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, eFlagsRegUCF cmp, label labl) %{ } emit_d8(cbuf, parity_disp); emit_cc(cbuf, $primary, $cop$$cmpcode); - int disp = l ? (l->loc_pos() - (cbuf.code_size() + 1)) : 0; + int disp = l ? (l->loc_pos() - (cbuf.insts_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"); diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index ba91cb79915..b0f73012f5f 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -619,62 +619,48 @@ void MachBreakpointNode::format(PhaseRegAlloc*, outputStream* st) const #endif // EMIT_RM() -void emit_rm(CodeBuffer &cbuf, int f1, int f2, int f3) -{ +void emit_rm(CodeBuffer &cbuf, int f1, int f2, int f3) { unsigned char c = (unsigned char) ((f1 << 6) | (f2 << 3) | f3); - *(cbuf.code_end()) = c; - cbuf.set_code_end(cbuf.code_end() + 1); + cbuf.insts()->emit_int8(c); } // EMIT_CC() -void emit_cc(CodeBuffer &cbuf, int f1, int f2) -{ +void emit_cc(CodeBuffer &cbuf, int f1, int f2) { unsigned char c = (unsigned char) (f1 | f2); - *(cbuf.code_end()) = c; - cbuf.set_code_end(cbuf.code_end() + 1); + cbuf.insts()->emit_int8(c); } // EMIT_OPCODE() -void emit_opcode(CodeBuffer &cbuf, int code) -{ - *(cbuf.code_end()) = (unsigned char) code; - cbuf.set_code_end(cbuf.code_end() + 1); +void emit_opcode(CodeBuffer &cbuf, int code) { + cbuf.insts()->emit_int8((unsigned char) code); } // EMIT_OPCODE() w/ relocation information void emit_opcode(CodeBuffer &cbuf, int code, relocInfo::relocType reloc, int offset, int format) { - cbuf.relocate(cbuf.inst_mark() + offset, reloc, format); + cbuf.relocate(cbuf.insts_mark() + offset, reloc, format); emit_opcode(cbuf, code); } // EMIT_D8() -void emit_d8(CodeBuffer &cbuf, int d8) -{ - *(cbuf.code_end()) = (unsigned char) d8; - cbuf.set_code_end(cbuf.code_end() + 1); +void emit_d8(CodeBuffer &cbuf, int d8) { + cbuf.insts()->emit_int8((unsigned char) d8); } // EMIT_D16() -void emit_d16(CodeBuffer &cbuf, int d16) -{ - *((short *)(cbuf.code_end())) = d16; - cbuf.set_code_end(cbuf.code_end() + 2); +void emit_d16(CodeBuffer &cbuf, int d16) { + cbuf.insts()->emit_int16(d16); } // EMIT_D32() -void emit_d32(CodeBuffer &cbuf, int d32) -{ - *((int *)(cbuf.code_end())) = d32; - cbuf.set_code_end(cbuf.code_end() + 4); +void emit_d32(CodeBuffer &cbuf, int d32) { + cbuf.insts()->emit_int32(d32); } // EMIT_D64() -void emit_d64(CodeBuffer &cbuf, int64_t d64) -{ - *((int64_t*) (cbuf.code_end())) = d64; - cbuf.set_code_end(cbuf.code_end() + 8); +void emit_d64(CodeBuffer &cbuf, int64_t d64) { + cbuf.insts()->emit_int64(d64); } // emit 32 bit value and construct relocation entry from relocInfo::relocType @@ -684,32 +670,24 @@ void emit_d32_reloc(CodeBuffer& cbuf, int format) { assert(reloc != relocInfo::external_word_type, "use 2-arg emit_d32_reloc"); - cbuf.relocate(cbuf.inst_mark(), reloc, format); - - *((int*) (cbuf.code_end())) = d32; - cbuf.set_code_end(cbuf.code_end() + 4); + cbuf.relocate(cbuf.insts_mark(), reloc, format); + cbuf.insts()->emit_int32(d32); } // emit 32 bit value and construct relocation entry from RelocationHolder -void emit_d32_reloc(CodeBuffer& cbuf, - int d32, - RelocationHolder const& rspec, - int format) -{ +void emit_d32_reloc(CodeBuffer& cbuf, int d32, RelocationHolder const& rspec, int format) { #ifdef ASSERT if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (intptr_t) Universe::non_oop_word()) { assert(oop((intptr_t)d32)->is_oop() && (ScavengeRootsInCode || !oop((intptr_t)d32)->is_scavengable()), "cannot embed scavengable oops in code"); } #endif - cbuf.relocate(cbuf.inst_mark(), rspec, format); - - *((int* )(cbuf.code_end())) = d32; - cbuf.set_code_end(cbuf.code_end() + 4); + cbuf.relocate(cbuf.insts_mark(), rspec, format); + cbuf.insts()->emit_int32(d32); } void emit_d32_reloc(CodeBuffer& cbuf, address addr) { - address next_ip = cbuf.code_end() + 4; + address next_ip = cbuf.insts_end() + 4; emit_d32_reloc(cbuf, (int) (addr - next_ip), external_word_Relocation::spec(addr), RELOC_DISP32); @@ -717,23 +695,13 @@ void emit_d32_reloc(CodeBuffer& cbuf, address addr) { // emit 64 bit value and construct relocation entry from relocInfo::relocType -void emit_d64_reloc(CodeBuffer& cbuf, - int64_t d64, - relocInfo::relocType reloc, - int format) -{ - cbuf.relocate(cbuf.inst_mark(), reloc, format); - - *((int64_t*) (cbuf.code_end())) = d64; - cbuf.set_code_end(cbuf.code_end() + 8); +void emit_d64_reloc(CodeBuffer& cbuf, int64_t d64, relocInfo::relocType reloc, int format) { + cbuf.relocate(cbuf.insts_mark(), reloc, format); + cbuf.insts()->emit_int64(d64); } // emit 64 bit value and construct relocation entry from RelocationHolder -void emit_d64_reloc(CodeBuffer& cbuf, - int64_t d64, - RelocationHolder const& rspec, - int format) -{ +void emit_d64_reloc(CodeBuffer& cbuf, int64_t d64, RelocationHolder const& rspec, int format) { #ifdef ASSERT if (rspec.reloc()->type() == relocInfo::oop_type && d64 != 0 && d64 != (int64_t) Universe::non_oop_word()) { @@ -741,10 +709,8 @@ void emit_d64_reloc(CodeBuffer& cbuf, "cannot embed scavengable oops in code"); } #endif - cbuf.relocate(cbuf.inst_mark(), rspec, format); - - *((int64_t*) (cbuf.code_end())) = d64; - cbuf.set_code_end(cbuf.code_end() + 8); + cbuf.relocate(cbuf.insts_mark(), rspec, format); + cbuf.insts()->emit_int64(d64); } // Access stack slot for load or store @@ -966,7 +932,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const } } - C->set_frame_complete(cbuf.code_end() - cbuf.code_begin()); + C->set_frame_complete(cbuf.insts_size()); #ifdef ASSERT if (VerifyStackAtCalls) { @@ -1050,11 +1016,11 @@ void MachEpilogNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const if (do_polling() && C->is_method_compilation()) { // testl %rax, off(%rip) // Opcode + ModRM + Disp32 == 6 bytes // XXX reg_mem doesn't support RIP-relative addressing yet - cbuf.set_inst_mark(); - cbuf.relocate(cbuf.inst_mark(), relocInfo::poll_return_type, 0); // XXX + cbuf.set_insts_mark(); + cbuf.relocate(cbuf.insts_mark(), relocInfo::poll_return_type, 0); // XXX emit_opcode(cbuf, 0x85); // testl emit_rm(cbuf, 0x0, RAX_enc, 0x5); // 00 rax 101 == 0x5 - // cbuf.inst_mark() is beginning of instruction + // cbuf.insts_mark() is beginning of instruction emit_d32_reloc(cbuf, os::get_polling_page()); // relocInfo::poll_return_type, } @@ -1607,8 +1573,8 @@ uint MachSpillCopyNode::implementation(CodeBuffer* cbuf, emit_opcode(*cbuf, 0x0F); emit_opcode(*cbuf, 0x7E); emit_rm(*cbuf, 0x3, - Matcher::_regEncode[dst_first] & 7, - Matcher::_regEncode[src_first] & 7); + Matcher::_regEncode[src_first] & 7, + Matcher::_regEncode[dst_first] & 7); #ifndef PRODUCT } else if (!do_size) { st->print("movdq %s, %s\t# spill", @@ -1637,8 +1603,8 @@ uint MachSpillCopyNode::implementation(CodeBuffer* cbuf, emit_opcode(*cbuf, 0x0F); emit_opcode(*cbuf, 0x7E); emit_rm(*cbuf, 0x3, - Matcher::_regEncode[dst_first] & 7, - Matcher::_regEncode[src_first] & 7); + Matcher::_regEncode[src_first] & 7, + Matcher::_regEncode[dst_first] & 7); #ifndef PRODUCT } else if (!do_size) { st->print("movdl %s, %s\t# spill", @@ -1814,9 +1780,9 @@ void emit_java_to_interp(CodeBuffer& cbuf) // movq rbx, 0 // jmp -5 # to self - address mark = cbuf.inst_mark(); // get mark within main instrs section + address mark = cbuf.insts_mark(); // get mark within main instrs section - // Note that the code buffer's inst_mark is always relative to insts. + // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a stub. MacroAssembler _masm(&cbuf); @@ -1830,7 +1796,7 @@ void emit_java_to_interp(CodeBuffer& cbuf) // This is recognized as unresolved by relocs/nativeinst/ic code __ jump(RuntimeAddress(__ pc())); - // Update current stubs pointer and restore code_end. + // Update current stubs pointer and restore insts_end. __ end_a_stub(); } @@ -1868,7 +1834,7 @@ void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { MacroAssembler masm(&cbuf); - uint code_size = cbuf.code_size(); + uint insts_size = cbuf.insts_size(); if (UseCompressedOops) { masm.load_klass(rscratch1, j_rarg0); masm.cmpptr(rax, rscratch1); @@ -1880,7 +1846,7 @@ void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const /* WARNING these NOPs are critical so that verified entry point is properly 4 bytes aligned for patching by NativeJump::patch_verified_entry() */ - int nops_cnt = 4 - ((cbuf.code_size() - code_size) & 0x3); + int nops_cnt = 4 - ((cbuf.insts_size() - insts_size) & 0x3); if (OptoBreakpoint) { // Leave space for int3 nops_cnt -= 1; @@ -1910,14 +1876,14 @@ uint size_exception_handler() int emit_exception_handler(CodeBuffer& cbuf) { - // Note that the code buffer's inst_mark is always relative to insts. + // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a handler. MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); if (base == NULL) return 0; // CodeBuffer::expand failed int offset = __ offset(); - __ jump(RuntimeAddress(OptoRuntime::exception_blob()->instructions_begin())); + __ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); __ end_a_stub(); return offset; @@ -1933,7 +1899,7 @@ uint size_deopt_handler() int emit_deopt_handler(CodeBuffer& cbuf) { - // Note that the code buffer's inst_mark is always relative to insts. + // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a handler. MacroAssembler _masm(&cbuf); address base = @@ -1962,7 +1928,7 @@ static void emit_double_constant(CodeBuffer& cbuf, double x) { address double_address = __ double_constant(x); cbuf.insts()->set_mark_off(mark); // preserve mark across masm shift emit_d32_reloc(cbuf, - (int) (double_address - cbuf.code_end() - 4), + (int) (double_address - cbuf.insts_end() - 4), internal_word_Relocation::spec(double_address), RELOC_DISP32); } @@ -1973,7 +1939,7 @@ static void emit_float_constant(CodeBuffer& cbuf, float x) { address float_address = __ float_constant(x); cbuf.insts()->set_mark_off(mark); // preserve mark across masm shift emit_d32_reloc(cbuf, - (int) (float_address - cbuf.code_end() - 4), + (int) (float_address - cbuf.insts_end() - 4), internal_word_Relocation::spec(float_address), RELOC_DISP32); } @@ -2481,14 +2447,14 @@ encode %{ %{ // JMP, CALL Label* l = $labl$$label; - emit_d32(cbuf, l ? (l->loc_pos() - (cbuf.code_size() + 4)) : 0); + emit_d32(cbuf, l ? (l->loc_pos() - (cbuf.insts_size() + 4)) : 0); %} enc_class LblShort(label labl) %{ // JMP, CALL Label* l = $labl$$label; - int disp = l ? (l->loc_pos() - (cbuf.code_size() + 1)) : 0; + int disp = l ? (l->loc_pos() - (cbuf.insts_size() + 1)) : 0; assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp"); emit_d8(cbuf, disp); %} @@ -2517,7 +2483,7 @@ encode %{ Label* l = $labl$$label; $$$emit8$primary; emit_cc(cbuf, $secondary, $cop$$cmpcode); - emit_d32(cbuf, l ? (l->loc_pos() - (cbuf.code_size() + 4)) : 0); + emit_d32(cbuf, l ? (l->loc_pos() - (cbuf.insts_size() + 4)) : 0); %} enc_class JccShort (cmpOp cop, label labl) @@ -2525,7 +2491,7 @@ encode %{ // JCC Label *l = $labl$$label; emit_cc(cbuf, $primary, $cop$$cmpcode); - int disp = l ? (l->loc_pos() - (cbuf.code_size() + 1)) : 0; + int disp = l ? (l->loc_pos() - (cbuf.insts_size() + 1)) : 0; assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp"); emit_d8(cbuf, disp); %} @@ -2609,22 +2575,22 @@ encode %{ %{ // CALL Java_To_Interpreter // This is the instruction starting address for relocation info. - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); $$$emit8$primary; // CALL directly to the runtime emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.code_end()) - 4), + (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), runtime_call_Relocation::spec(), RELOC_DISP32); %} enc_class preserve_SP %{ - debug_only(int off0 = cbuf.code_size()); + debug_only(int off0 = cbuf.insts_size()); MacroAssembler _masm(&cbuf); // RBP is preserved across all calls, even compiled calls. // Use it to preserve RSP in places where the callee might change the SP. __ movptr(rbp_mh_SP_save, rsp); - debug_only(int off1 = cbuf.code_size()); + debug_only(int off1 = cbuf.insts_size()); assert(off1 - off0 == preserve_SP_size(), "correct size prediction"); %} @@ -2638,22 +2604,22 @@ encode %{ // JAVA STATIC CALL // CALL to fixup routine. Fixup routine uses ScopeDesc info to // determine who we intended to call. - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); $$$emit8$primary; if (!_method) { emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.code_end()) - 4), + (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), runtime_call_Relocation::spec(), RELOC_DISP32); } else if (_optimized_virtual) { emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.code_end()) - 4), + (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), opt_virtual_call_Relocation::spec(), RELOC_DISP32); } else { emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.code_end()) - 4), + (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), static_call_Relocation::spec(), RELOC_DISP32); } @@ -2669,7 +2635,7 @@ encode %{ // !!!!! // Generate "movq rax, -1", placeholder instruction to load oop-info // emit_call_dynamic_prologue( cbuf ); - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); // movq rax, -1 emit_opcode(cbuf, Assembler::REX_W); @@ -2677,13 +2643,13 @@ encode %{ emit_d64_reloc(cbuf, (int64_t) Universe::non_oop_word(), oop_Relocation::spec_for_immediate(), RELOC_IMM64); - address virtual_call_oop_addr = cbuf.inst_mark(); + address virtual_call_oop_addr = cbuf.insts_mark(); // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine // who we intended to call. - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); $$$emit8$primary; emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.code_end()) - 4), + (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), virtual_call_Relocation::spec(virtual_call_oop_addr), RELOC_DISP32); %} @@ -2697,7 +2663,7 @@ encode %{ // assert(-0x80 <= disp && disp < 0x80, "compiled_code_offset isn't small"); // callq *disp(%rax) - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); $$$emit8$primary; if (disp < 0x80) { emit_rm(cbuf, 0x01, $secondary, RAX_enc); // R/M byte @@ -3729,10 +3695,10 @@ encode %{ enc_class enc_rethrow() %{ - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, 0xE9); // jmp entry emit_d32_reloc(cbuf, - (int) (OptoRuntime::rethrow_stub() - cbuf.code_end() - 4), + (int) (OptoRuntime::rethrow_stub() - cbuf.insts_end() - 4), runtime_call_Relocation::spec(), RELOC_DISP32); %} @@ -3742,7 +3708,7 @@ encode %{ int dstenc = $dst$$reg; address signmask_address = (address) StubRoutines::x86::float_sign_mask(); - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); if (dstenc >= 8) { emit_opcode(cbuf, Assembler::REX_R); dstenc -= 8; @@ -3759,7 +3725,7 @@ encode %{ int dstenc = $dst$$reg; address signmask_address = (address) StubRoutines::x86::double_sign_mask(); - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, 0x66); if (dstenc >= 8) { emit_opcode(cbuf, Assembler::REX_R); @@ -3777,7 +3743,7 @@ encode %{ int dstenc = $dst$$reg; address signflip_address = (address) StubRoutines::x86::float_sign_flip(); - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); if (dstenc >= 8) { emit_opcode(cbuf, Assembler::REX_R); dstenc -= 8; @@ -3794,7 +3760,7 @@ encode %{ int dstenc = $dst$$reg; address signflip_address = (address) StubRoutines::x86::double_sign_flip(); - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, 0x66); if (dstenc >= 8) { emit_opcode(cbuf, Assembler::REX_R); @@ -3846,11 +3812,11 @@ encode %{ encode_RegMem(cbuf, srcenc, RSP_enc, 0x4, 0, 0, false); // 2 bytes // call f2i_fixup - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, 0xE8); emit_d32_reloc(cbuf, (int) - (StubRoutines::x86::f2i_fixup() - cbuf.code_end() - 4), + (StubRoutines::x86::f2i_fixup() - cbuf.insts_end() - 4), runtime_call_Relocation::spec(), RELOC_DISP32); @@ -3870,7 +3836,7 @@ encode %{ address const_address = (address) StubRoutines::x86::double_sign_flip(); // cmpq $dst, [0x8000000000000000] - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, dstenc < 8 ? Assembler::REX_W : Assembler::REX_WR); emit_opcode(cbuf, 0x39); // XXX reg_mem doesn't support RIP-relative addressing yet @@ -3904,11 +3870,11 @@ encode %{ encode_RegMem(cbuf, srcenc, RSP_enc, 0x4, 0, 0, false); // 2 bytes // call f2l_fixup - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, 0xE8); emit_d32_reloc(cbuf, (int) - (StubRoutines::x86::f2l_fixup() - cbuf.code_end() - 4), + (StubRoutines::x86::f2l_fixup() - cbuf.insts_end() - 4), runtime_call_Relocation::spec(), RELOC_DISP32); @@ -3960,11 +3926,11 @@ encode %{ encode_RegMem(cbuf, srcenc, RSP_enc, 0x4, 0, 0, false); // 2 bytes // call d2i_fixup - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, 0xE8); emit_d32_reloc(cbuf, (int) - (StubRoutines::x86::d2i_fixup() - cbuf.code_end() - 4), + (StubRoutines::x86::d2i_fixup() - cbuf.insts_end() - 4), runtime_call_Relocation::spec(), RELOC_DISP32); @@ -3984,7 +3950,7 @@ encode %{ address const_address = (address) StubRoutines::x86::double_sign_flip(); // cmpq $dst, [0x8000000000000000] - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, dstenc < 8 ? Assembler::REX_W : Assembler::REX_WR); emit_opcode(cbuf, 0x39); // XXX reg_mem doesn't support RIP-relative addressing yet @@ -4018,11 +3984,11 @@ encode %{ encode_RegMem(cbuf, srcenc, RSP_enc, 0x4, 0, 0, false); // 2 bytes // call d2l_fixup - cbuf.set_inst_mark(); + cbuf.set_insts_mark(); emit_opcode(cbuf, 0xE8); emit_d32_reloc(cbuf, (int) - (StubRoutines::x86::d2l_fixup() - cbuf.code_end() - 4), + (StubRoutines::x86::d2l_fixup() - cbuf.insts_end() - 4), runtime_call_Relocation::spec(), RELOC_DISP32); @@ -4042,11 +4008,11 @@ encode %{ %{ // testl %rax, off(%rip) // Opcode + ModRM + Disp32 == 6 bytes // XXX reg_mem doesn't support RIP-relative addressing yet - cbuf.set_inst_mark(); - cbuf.relocate(cbuf.inst_mark(), relocInfo::poll_type, 0); // XXX + cbuf.set_insts_mark(); + cbuf.relocate(cbuf.insts_mark(), relocInfo::poll_type, 0); // XXX emit_opcode(cbuf, 0x85); // testl emit_rm(cbuf, 0x0, RAX_enc, 0x5); // 00 rax 101 == 0x5 - // cbuf.inst_mark() is beginning of instruction + // cbuf.insts_mark() is beginning of instruction emit_d32_reloc(cbuf, os::get_polling_page()); // relocInfo::poll_type, %} @@ -12304,7 +12270,7 @@ instruct jmpConUCF2(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ 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; + parity_disp = l ? (l->loc_pos() - (cbuf.insts_size() + 4)) : 0; } else if ($cop$$cmpcode == Assembler::equal) { parity_disp = 6; } else { @@ -12313,7 +12279,7 @@ instruct jmpConUCF2(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ emit_d32(cbuf, parity_disp); $$$emit8$primary; emit_cc(cbuf, $secondary, $cop$$cmpcode); - int disp = l ? (l->loc_pos() - (cbuf.code_size() + 4)) : 0; + int disp = l ? (l->loc_pos() - (cbuf.insts_size() + 4)) : 0; emit_d32(cbuf, disp); %} ins_pipe(pipe_jcc); @@ -12508,7 +12474,7 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ 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; + parity_disp = l ? (l->loc_pos() - (cbuf.insts_size() + 1)) : 0; } else if ($cop$$cmpcode == Assembler::equal) { parity_disp = 2; } else { @@ -12516,7 +12482,7 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ } emit_d8(cbuf, parity_disp); emit_cc(cbuf, $primary, $cop$$cmpcode); - int disp = l ? (l->loc_pos() - (cbuf.code_size() + 1)) : 0; + int disp = l ? (l->loc_pos() - (cbuf.insts_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"); diff --git a/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.inline.hpp b/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.inline.hpp index 702a165ef29..a35809f0a5b 100644 --- a/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.inline.hpp +++ b/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007 Red Hat, Inc. + * Copyright 2007, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -268,7 +268,7 @@ inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) { return op1 - op2; } -inline jint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { +inline juint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { return ((juint) op1) >> (op2 & 0x1F); } diff --git a/hotspot/src/cpu/zero/vm/javaFrameAnchor_zero.hpp b/hotspot/src/cpu/zero/vm/javaFrameAnchor_zero.hpp index 5748301c096..0763790b64e 100644 --- a/hotspot/src/cpu/zero/vm/javaFrameAnchor_zero.hpp +++ b/hotspot/src/cpu/zero/vm/javaFrameAnchor_zero.hpp @@ -82,6 +82,10 @@ return _last_Java_fp; } + address last_Java_pc() const { + return _last_Java_pc; + } + static ByteSize last_Java_fp_offset() { return byte_offset_of(JavaFrameAnchor, _last_Java_fp); } diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 8635a3d411f..e3e117eb5fb 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -2597,10 +2597,14 @@ get_stack_bounds(uintptr_t *bottom, uintptr_t *top) // where we're going to put our guard pages, truncate the mapping at // that point by munmap()ping it. This ensures that when we later // munmap() the guard pages we don't leave a hole in the stack -// mapping. +// mapping. This only affects the main/initial thread, but guard +// against future OS changes bool os::create_stack_guard_pages(char* addr, size_t size) { uintptr_t stack_extent, stack_base; - if (get_stack_bounds(&stack_extent, &stack_base)) { + bool chk_bounds = NOT_DEBUG(os::Linux::is_initial_thread()) DEBUG_ONLY(true); + if (chk_bounds && get_stack_bounds(&stack_extent, &stack_base)) { + assert(os::Linux::is_initial_thread(), + "growable stack in non-initial thread"); if (stack_extent < (uintptr_t)addr) ::munmap((void*)stack_extent, (uintptr_t)addr - stack_extent); } @@ -2609,10 +2613,15 @@ bool os::create_stack_guard_pages(char* addr, size_t size) { } // If this is a growable mapping, remove the guard pages entirely by -// munmap()ping them. If not, just call uncommit_memory(). +// munmap()ping them. If not, just call uncommit_memory(). This only +// affects the main/initial thread, but guard against future OS changes bool os::remove_stack_guard_pages(char* addr, size_t size) { uintptr_t stack_extent, stack_base; - if (get_stack_bounds(&stack_extent, &stack_base)) { + bool chk_bounds = NOT_DEBUG(os::Linux::is_initial_thread()) DEBUG_ONLY(true); + if (chk_bounds && get_stack_bounds(&stack_extent, &stack_base)) { + assert(os::Linux::is_initial_thread(), + "growable stack in non-initial thread"); + return ::munmap(addr, size) == 0; } diff --git a/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp b/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp index d39ffdd3fb7..d60d0bb6469 100644 --- a/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp +++ b/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp @@ -230,7 +230,8 @@ int generateJvmOffsets(GEN_variant gen_variant) { GEN_OFFS(CodeBlob, _name); GEN_OFFS(CodeBlob, _header_size); - GEN_OFFS(CodeBlob, _instructions_offset); + GEN_OFFS(CodeBlob, _content_offset); + GEN_OFFS(CodeBlob, _code_offset); GEN_OFFS(CodeBlob, _data_offset); GEN_OFFS(CodeBlob, _frame_size); printf("\n"); diff --git a/hotspot/src/os/solaris/dtrace/libjvm_db.c b/hotspot/src/os/solaris/dtrace/libjvm_db.c index 691cbb7be8f..5e1d626800f 100644 --- a/hotspot/src/os/solaris/dtrace/libjvm_db.c +++ b/hotspot/src/os/solaris/dtrace/libjvm_db.c @@ -124,7 +124,7 @@ typedef struct Nmethod_t { uint64_t pc_desc; int32_t orig_pc_offset; /* _orig_pc_offset */ - int32_t instrs_beg; /* _instructions_offset */ + int32_t instrs_beg; /* _code_offset */ int32_t instrs_end; int32_t deopt_beg; /* _deoptimize_offset */ int32_t scopes_data_beg; /* _scopes_data_offset */ @@ -587,7 +587,7 @@ static int nmethod_info(Nmethod_t *N) fprintf(stderr, "\t nmethod_info: BEGIN \n"); /* Instructions */ - err = ps_pread(J->P, nm + OFFSET_CodeBlob_instructions_offset, &N->instrs_beg, SZ32); + err = ps_pread(J->P, nm + OFFSET_CodeBlob_code_offset, &N->instrs_beg, SZ32); CHECK_FAIL(err); err = ps_pread(J->P, nm + OFFSET_CodeBlob_data_offset, &N->instrs_end, SZ32); CHECK_FAIL(err); diff --git a/hotspot/src/os_cpu/linux_sparc/vm/orderAccess_linux_sparc.inline.hpp b/hotspot/src/os_cpu/linux_sparc/vm/orderAccess_linux_sparc.inline.hpp index 4ff88cfdbbe..2770baaabef 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/orderAccess_linux_sparc.inline.hpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/orderAccess_linux_sparc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,8 +36,8 @@ inline void OrderAccess::acquire() { } inline void OrderAccess::release() { - jint* dummy = (jint*)&dummy; - __asm__ volatile("stw %%g0, [%0]" : : "r" (dummy) : "memory"); + jint* local_dummy = (jint*)&local_dummy; + __asm__ volatile("stw %%g0, [%0]" : : "r" (local_dummy) : "memory"); } inline void OrderAccess::fence() { diff --git a/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp b/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp index a4f6c17d7ae..d487ece69a3 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp +++ b/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,16 +30,18 @@ inline void OrderAccess::loadstore() { acquire(); } inline void OrderAccess::storeload() { fence(); } inline void OrderAccess::acquire() { - volatile intptr_t dummy; + volatile intptr_t local_dummy; #ifdef AMD64 - __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (dummy) : : "memory"); + __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (local_dummy) : : "memory"); #else - __asm__ volatile ("movl 0(%%esp),%0" : "=r" (dummy) : : "memory"); + __asm__ volatile ("movl 0(%%esp),%0" : "=r" (local_dummy) : : "memory"); #endif // AMD64 } inline void OrderAccess::release() { - dummy = 0; + // Avoid hitting the same cache-line from + // different threads. + volatile jint local_dummy = 0; } inline void OrderAccess::fence() { diff --git a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp index ce9d86fdd60..fd78628b3eb 100644 --- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp +++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp @@ -435,22 +435,22 @@ extern "C" { void _Copy_arrayof_conjoint_bytes(HeapWord* from, HeapWord* to, size_t count) { - ShouldNotCallThis(); + memmove(to, from, count); } void _Copy_arrayof_conjoint_jshorts(HeapWord* from, HeapWord* to, size_t count) { - ShouldNotCallThis(); + memmove(to, from, count * 2); } void _Copy_arrayof_conjoint_jints(HeapWord* from, HeapWord* to, size_t count) { - ShouldNotCallThis(); + memmove(to, from, count * 4); } void _Copy_arrayof_conjoint_jlongs(HeapWord* from, HeapWord* to, size_t count) { - ShouldNotCallThis(); + memmove(to, from, count * 8); } }; diff --git a/hotspot/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp b/hotspot/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp index 15dba5fff97..8551eafce62 100644 --- a/hotspot/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp +++ b/hotspot/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. + * Copyright 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,9 @@ * */ -// This file is intentionally empty +#include "incls/_precompiled.incl" +#include "incls/_thread_linux_zero.cpp.incl" -void JavaThread::cache_global_variables() { } +void JavaThread::cache_global_variables() { + // nothing to do +} diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp index 2646977ce8f..6075e010687 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,8 +42,8 @@ inline void OrderAccess::acquire() { } inline void OrderAccess::release() { - jint* dummy = (jint*)&dummy; - __asm__ volatile("stw %%g0, [%0]" : : "r" (dummy) : "memory"); + jint* local_dummy = (jint*)&local_dummy; + __asm__ volatile("stw %%g0, [%0]" : : "r" (local_dummy) : "memory"); } inline void OrderAccess::fence() { @@ -57,7 +57,9 @@ inline void OrderAccess::acquire() { } inline void OrderAccess::release() { - dummy = 0; + // Avoid hitting the same cache-line from + // different threads. + volatile jint local_dummy = 0; } inline void OrderAccess::fence() { diff --git a/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp b/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp index 7165cde66d0..84c1ce9238d 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,9 @@ inline void OrderAccess::acquire() { } inline void OrderAccess::release() { - dummy = 0; + // Avoid hitting the same cache-line from + // different threads. + volatile jint local_dummy = 0; } inline void OrderAccess::fence() { @@ -53,11 +55,11 @@ inline void OrderAccess::fence() { extern "C" { inline void _OrderAccess_acquire() { - volatile intptr_t dummy; + volatile intptr_t local_dummy; #ifdef AMD64 - __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (dummy) : : "memory"); + __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (local_dummy) : : "memory"); #else - __asm__ volatile ("movl 0(%%esp),%0" : "=r" (dummy) : : "memory"); + __asm__ volatile ("movl 0(%%esp),%0" : "=r" (local_dummy) : : "memory"); #endif // AMD64 } inline void _OrderAccess_fence() { diff --git a/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp b/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp index 4a5ac91b18d..1ccddc4d397 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ inline void OrderAccess::acquire() { inline void OrderAccess::release() { // A volatile store has release semantics. - dummy = 0; + volatile jint local_dummy = 0; } inline void OrderAccess::fence() { diff --git a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp index 8cc55b78c3d..cc32675875f 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -149,8 +149,8 @@ bool os::register_code_area(char *low, char *high) { // If we are using Vectored Exceptions we don't need this registration if (UseVectoredExceptions) return true; - BufferBlob* b = BufferBlob::create("CodeCache Exception Handler", sizeof (DynamicCodeData)); - CodeBuffer cb(b->instructions_begin(), b->instructions_size()); + BufferBlob* blob = BufferBlob::create("CodeCache Exception Handler", sizeof(DynamicCodeData)); + CodeBuffer cb(blob); MacroAssembler* masm = new MacroAssembler(&cb); pDCD = (pDynamicCodeData) masm->pc(); diff --git a/hotspot/src/os_cpu/windows_x86/vm/windows_x86_32.ad b/hotspot/src/os_cpu/windows_x86/vm/windows_x86_32.ad index 88eccf22036..32b7b2973ea 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/windows_x86_32.ad +++ b/hotspot/src/os_cpu/windows_x86/vm/windows_x86_32.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -141,8 +141,7 @@ source %{ // emit an interrupt that is caught by the debugger void emit_break(CodeBuffer &cbuf) { - *(cbuf.code_end()) = (unsigned char)(0xcc); - cbuf.set_code_end(cbuf.code_end() + 1); + cbuf.insts()->emit_int8((unsigned char) 0xcc); } void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { diff --git a/hotspot/src/os_cpu/windows_x86/vm/windows_x86_64.ad b/hotspot/src/os_cpu/windows_x86/vm/windows_x86_64.ad index 3e1b573f867..69374f8e4de 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/windows_x86_64.ad +++ b/hotspot/src/os_cpu/windows_x86/vm/windows_x86_64.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -144,8 +144,7 @@ int MachCallRuntimeNode::ret_addr_offset() // emit an interrupt that is caught by the debugger void emit_break(CodeBuffer &cbuf) { - *(cbuf.code_end()) = (unsigned char)(0xcc); - cbuf.set_code_end(cbuf.code_end() + 1); + cbuf.insts()->emit_int8((unsigned char) 0xcc); } void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { diff --git a/hotspot/src/share/vm/adlc/output_c.cpp b/hotspot/src/share/vm/adlc/output_c.cpp index 393fd238b27..75cdcacb997 100644 --- a/hotspot/src/share/vm/adlc/output_c.cpp +++ b/hotspot/src/share/vm/adlc/output_c.cpp @@ -2482,7 +2482,7 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) { } // Save current instruction's starting address (helps with relocation). - fprintf( fp, " cbuf.set_inst_mark();\n"); + fprintf(fp, " cbuf.set_insts_mark();\n"); // // // idx0 is only needed for syntactic purposes and only by "storeSSI" // fprintf( fp, " unsigned idx0 = 0;\n"); diff --git a/hotspot/src/share/vm/asm/codeBuffer.cpp b/hotspot/src/share/vm/asm/codeBuffer.cpp index 77e7cdb8727..d7e4bb54d3b 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.cpp +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,12 +74,11 @@ typedef CodeBuffer::csize_t csize_t; // file-local definition -// external buffer, in a predefined CodeBlob or other buffer area +// External buffer, in a predefined CodeBlob. // Important: The code_start must be taken exactly, and not realigned. -CodeBuffer::CodeBuffer(address code_start, csize_t code_size) { - assert(code_start != NULL, "sanity"); +CodeBuffer::CodeBuffer(CodeBlob* blob) { initialize_misc("static buffer"); - initialize(code_start, code_size); + initialize(blob->content_begin(), blob->content_size()); assert(verify_section_allocation(), "initial use of buffer OK"); } @@ -99,7 +98,7 @@ void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) { // Set up various pointers into the blob. initialize(_total_start, _total_size); - assert((uintptr_t)code_begin() % CodeEntryAlignment == 0, "instruction start not code entry aligned"); + assert((uintptr_t)insts_begin() % CodeEntryAlignment == 0, "instruction start not code entry aligned"); pd_initialize(); @@ -144,13 +143,6 @@ void CodeBuffer::initialize_oop_recorder(OopRecorder* r) { void CodeBuffer::initialize_section_size(CodeSection* cs, csize_t size) { assert(cs != &_insts, "insts is the memory provider, not the consumer"); -#ifdef ASSERT - for (int n = (int)SECT_INSTS+1; n < (int)SECT_LIMIT; n++) { - CodeSection* prevCS = code_section(n); - if (prevCS == cs) break; - assert(!prevCS->is_allocated(), "section allocation must be in reverse order"); - } -#endif csize_t slop = CodeSection::end_slop(); // margin between sections int align = cs->alignment(); assert(is_power_of_2(align), "sanity"); @@ -192,21 +184,21 @@ void CodeBuffer::freeze_section(CodeSection* cs) { void CodeBuffer::set_blob(BufferBlob* blob) { _blob = blob; if (blob != NULL) { - address start = blob->instructions_begin(); - address end = blob->instructions_end(); + address start = blob->content_begin(); + address end = blob->content_end(); // Round up the starting address. int align = _insts.alignment(); start += (-(intptr_t)start) & (align-1); _total_start = start; _total_size = end - start; } else { - #ifdef ASSERT +#ifdef ASSERT // Clean out dangling pointers. _total_start = badAddress; + _consts._start = _consts._end = badAddress; _insts._start = _insts._end = badAddress; _stubs._start = _stubs._end = badAddress; - _consts._start = _consts._end = badAddress; - #endif //ASSERT +#endif //ASSERT } } @@ -222,9 +214,9 @@ const char* CodeBuffer::code_section_name(int n) { return NULL; #else //PRODUCT switch (n) { + case SECT_CONSTS: return "consts"; case SECT_INSTS: return "insts"; case SECT_STUBS: return "stubs"; - case SECT_CONSTS: return "consts"; default: return NULL; } #endif //PRODUCT @@ -422,21 +414,21 @@ void CodeSection::expand_locs(int new_capacity) { /// The pattern is the same for all functions. /// We iterate over all the sections, padding each to alignment. -csize_t CodeBuffer::total_code_size() const { - csize_t code_size_so_far = 0; +csize_t CodeBuffer::total_content_size() const { + csize_t size_so_far = 0; for (int n = 0; n < (int)SECT_LIMIT; n++) { const CodeSection* cs = code_section(n); if (cs->is_empty()) continue; // skip trivial section - code_size_so_far = cs->align_at_start(code_size_so_far); - code_size_so_far += cs->size(); + size_so_far = cs->align_at_start(size_so_far); + size_so_far += cs->size(); } - return code_size_so_far; + return size_so_far; } void CodeBuffer::compute_final_layout(CodeBuffer* dest) const { address buf = dest->_total_start; csize_t buf_offset = 0; - assert(dest->_total_size >= total_code_size(), "must be big enough"); + assert(dest->_total_size >= total_content_size(), "must be big enough"); { // not sure why this is here, but why not... @@ -446,12 +438,11 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const { const CodeSection* prev_cs = NULL; CodeSection* prev_dest_cs = NULL; - for (int n = 0; n < (int)SECT_LIMIT; n++) { + + for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) { // figure compact layout of each section const CodeSection* cs = code_section(n); - address cstart = cs->start(); - address cend = cs->end(); - csize_t csize = cend - cstart; + csize_t csize = cs->size(); CodeSection* dest_cs = dest->code_section(n); if (!cs->is_empty()) { @@ -464,7 +455,7 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const { prev_dest_cs->_limit += padding; } #ifdef ASSERT - if (prev_cs != NULL && prev_cs->is_frozen() && n < SECT_CONSTS) { + if (prev_cs != NULL && prev_cs->is_frozen() && n < (SECT_LIMIT - 1)) { // Make sure the ends still match up. // This is important because a branch in a frozen section // might target code in a following section, via a Label, @@ -489,33 +480,29 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const { } // Done calculating sections; did it come out to the right end? - assert(buf_offset == total_code_size(), "sanity"); + assert(buf_offset == total_content_size(), "sanity"); assert(dest->verify_section_allocation(), "final configuration works"); } -csize_t CodeBuffer::total_offset_of(address addr) const { - csize_t code_size_so_far = 0; - for (int n = 0; n < (int)SECT_LIMIT; n++) { - const CodeSection* cs = code_section(n); - if (!cs->is_empty()) { - code_size_so_far = cs->align_at_start(code_size_so_far); +csize_t CodeBuffer::total_offset_of(CodeSection* cs) const { + csize_t size_so_far = 0; + for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) { + const CodeSection* cur_cs = code_section(n); + if (!cur_cs->is_empty()) { + size_so_far = cur_cs->align_at_start(size_so_far); } - if (cs->contains2(addr)) { - return code_size_so_far + (addr - cs->start()); + if (cur_cs->index() == cs->index()) { + return size_so_far; } - code_size_so_far += cs->size(); + size_so_far += cur_cs->size(); } -#ifndef PRODUCT - tty->print_cr("Dangling address " PTR_FORMAT " in:", addr); - ((CodeBuffer*)this)->print(); -#endif ShouldNotReachHere(); return -1; } csize_t CodeBuffer::total_relocation_size() const { csize_t lsize = copy_relocations_to(NULL); // dry run only - csize_t csize = total_code_size(); + csize_t csize = total_content_size(); csize_t total = RelocIterator::locs_and_index_size(csize, lsize); return (csize_t) align_size_up(total, HeapWordSize); } @@ -534,7 +521,7 @@ csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const { csize_t code_end_so_far = 0; csize_t code_point_so_far = 0; - for (int n = 0; n < (int)SECT_LIMIT; n++) { + for (int n = (int) SECT_FIRST; n < (int)SECT_LIMIT; n++) { // pull relocs out of each section const CodeSection* cs = code_section(n); assert(!(cs->is_empty() && cs->locs_count() > 0), "sanity"); @@ -601,7 +588,7 @@ csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const { buf_offset += sizeof(relocInfo); } - assert(code_end_so_far == total_code_size(), "sanity"); + assert(code_end_so_far == total_content_size(), "sanity"); // Account for index: if (buf != NULL) { @@ -621,9 +608,8 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) { } #endif //PRODUCT - CodeBuffer dest(dest_blob->instructions_begin(), - dest_blob->instructions_size()); - assert(dest_blob->instructions_size() >= total_code_size(), "good sizing"); + CodeBuffer dest(dest_blob); + assert(dest_blob->content_size() >= total_content_size(), "good sizing"); this->compute_final_layout(&dest); relocate_code_to(&dest); @@ -631,18 +617,20 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) { dest_blob->set_comments(_comments); // Done moving code bytes; were they the right size? - assert(round_to(dest.total_code_size(), oopSize) == dest_blob->instructions_size(), "sanity"); + assert(round_to(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity"); // Flush generated code - ICache::invalidate_range(dest_blob->instructions_begin(), - dest_blob->instructions_size()); + ICache::invalidate_range(dest_blob->code_begin(), dest_blob->code_size()); } -// Move all my code into another code buffer. -// Consult applicable relocs to repair embedded addresses. +// Move all my code into another code buffer. Consult applicable +// relocs to repair embedded addresses. The layout in the destination +// CodeBuffer is different to the source CodeBuffer: the destination +// CodeBuffer gets the final layout (consts, insts, stubs in order of +// ascending address). void CodeBuffer::relocate_code_to(CodeBuffer* dest) const { DEBUG_ONLY(address dest_end = dest->_total_start + dest->_total_size); - for (int n = 0; n < (int)SECT_LIMIT; n++) { + for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) { // pull code out of each section const CodeSection* cs = code_section(n); if (cs->is_empty()) continue; // skip trivial section @@ -684,20 +672,19 @@ csize_t CodeBuffer::figure_expanded_capacities(CodeSection* which_cs, csize_t* new_capacity) { csize_t new_total_cap = 0; - int prev_n = -1; - for (int n = 0; n < (int)SECT_LIMIT; n++) { + for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) { const CodeSection* sect = code_section(n); if (!sect->is_empty()) { - // Compute initial padding; assign it to the previous non-empty guy. - // Cf. compute_final_layout. + // Compute initial padding; assign it to the previous section, + // even if it's empty (e.g. consts section can be empty). + // Cf. compute_final_layout csize_t padding = sect->align_at_start(new_total_cap) - new_total_cap; if (padding != 0) { new_total_cap += padding; - assert(prev_n >= 0, "sanity"); - new_capacity[prev_n] += padding; + assert(n - 1 >= SECT_FIRST, "sanity"); + new_capacity[n - 1] += padding; } - prev_n = n; } csize_t exp = sect->size(); // 100% increase @@ -777,11 +764,11 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) { this->_before_expand = bxp; // Give each section its required (expanded) capacity. - for (int n = (int)SECT_LIMIT-1; n >= SECT_INSTS; n--) { + for (int n = (int)SECT_LIMIT-1; n >= SECT_FIRST; n--) { CodeSection* cb_sect = cb.code_section(n); CodeSection* this_sect = code_section(n); if (new_capacity[n] == 0) continue; // already nulled out - if (n > SECT_INSTS) { + if (n != SECT_INSTS) { cb.initialize_section_size(cb_sect, new_capacity[n]); } assert(cb_sect->capacity() >= new_capacity[n], "big enough"); @@ -844,20 +831,25 @@ bool CodeBuffer::verify_section_allocation() { if (tstart == badAddress) return true; // smashed by set_blob(NULL) address tend = tstart + _total_size; if (_blob != NULL) { - assert(tstart >= _blob->instructions_begin(), "sanity"); - assert(tend <= _blob->instructions_end(), "sanity"); + assert(tstart >= _blob->content_begin(), "sanity"); + assert(tend <= _blob->content_end(), "sanity"); } - address tcheck = tstart; // advancing pointer to verify disjointness - for (int n = 0; n < (int)SECT_LIMIT; n++) { + // Verify disjointness. + for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) { CodeSection* sect = code_section(n); - if (!sect->is_allocated()) continue; - assert(sect->start() >= tcheck, "sanity"); - tcheck = sect->start(); - assert((intptr_t)tcheck % sect->alignment() == 0 + if (!sect->is_allocated() || sect->is_empty()) continue; + assert((intptr_t)sect->start() % sect->alignment() == 0 || sect->is_empty() || _blob == NULL, "start is aligned"); - assert(sect->end() >= tcheck, "sanity"); - assert(sect->end() <= tend, "sanity"); + for (int m = (int) SECT_FIRST; m < (int) SECT_LIMIT; m++) { + CodeSection* other = code_section(m); + if (!other->is_allocated() || other == sect) continue; + assert(!other->contains(sect->start() ), "sanity"); + // limit is an exclusive address and can be the start of another + // section. + assert(!other->contains(sect->limit() - 1), "sanity"); + } + assert(sect->end() <= tend, "sanity"); } return true; } @@ -981,13 +973,13 @@ void CodeComments::free() { void CodeBuffer::decode() { - Disassembler::decode(decode_begin(), code_end()); - _decode_begin = code_end(); + Disassembler::decode(decode_begin(), insts_end()); + _decode_begin = insts_end(); } void CodeBuffer::skip_decode() { - _decode_begin = code_end(); + _decode_begin = insts_end(); } diff --git a/hotspot/src/share/vm/asm/codeBuffer.hpp b/hotspot/src/share/vm/asm/codeBuffer.hpp index 8e4a4ea323c..16880dcfadd 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.hpp +++ b/hotspot/src/share/vm/asm/codeBuffer.hpp @@ -186,6 +186,12 @@ class CodeSection VALUE_OBJ_CLASS_SPEC { _locs_point = pc; } + // Code emission + void emit_int8 (int8_t x) { *((int8_t*) end()) = x; set_end(end() + 1); } + void emit_int16(int16_t x) { *((int16_t*) end()) = x; set_end(end() + 2); } + void emit_int32(int32_t x) { *((int32_t*) end()) = x; set_end(end() + 4); } + void emit_int64(int64_t x) { *((int64_t*) end()) = x; set_end(end() + 8); } + // Share a scratch buffer for relocinfo. (Hacky; saves a resource allocation.) void initialize_shared_locs(relocInfo* buf, int length); @@ -283,10 +289,12 @@ class CodeBuffer: public StackObj { public: typedef int csize_t; // code size type; would be size_t except for history enum { - // Here is the list of all possible sections, in order of ascending address. + // Here is the list of all possible sections. The order reflects + // the final layout. + SECT_FIRST = 0, + SECT_CONSTS = SECT_FIRST, // Non-instruction data: Floats, jump tables, etc. SECT_INSTS, // Executable instructions. SECT_STUBS, // Outbound trampolines for supporting call sites. - SECT_CONSTS, // Non-instruction data: Floats, jump tables, etc. SECT_LIMIT, SECT_NONE = -1 }; @@ -298,9 +306,9 @@ class CodeBuffer: public StackObj { const char* _name; + CodeSection _consts; // constants, jump tables CodeSection _insts; // instructions (the main section) CodeSection _stubs; // stubs (call site support), deopt, exception handling - CodeSection _consts; // constants, jump tables CodeBuffer* _before_expand; // dead buffer, from before the last expansion @@ -328,9 +336,9 @@ class CodeBuffer: public StackObj { } void initialize(address code_start, csize_t code_size) { + _consts.initialize_outer(this, SECT_CONSTS); _insts.initialize_outer(this, SECT_INSTS); _stubs.initialize_outer(this, SECT_STUBS); - _consts.initialize_outer(this, SECT_CONSTS); _total_start = code_start; _total_size = code_size; // Initialize the main section: @@ -374,9 +382,17 @@ class CodeBuffer: public StackObj { public: // (1) code buffer referring to pre-allocated instruction memory - CodeBuffer(address code_start, csize_t code_size); + CodeBuffer(address code_start, csize_t code_size) { + assert(code_start != NULL, "sanity"); + initialize_misc("static buffer"); + initialize(code_start, code_size); + assert(verify_section_allocation(), "initial use of buffer OK"); + } - // (2) code buffer allocating codeBlob memory for code & relocation + // (2) CodeBuffer referring to pre-allocated CodeBlob. + CodeBuffer(CodeBlob* blob); + + // (3) code buffer allocating codeBlob memory for code & relocation // info but with lazy initialization. The name must be something // informative. CodeBuffer(const char* name) { @@ -384,7 +400,7 @@ class CodeBuffer: public StackObj { } - // (3) code buffer allocating codeBlob memory for code & relocation + // (4) code buffer allocating codeBlob memory for code & relocation // info. The name must be something informative and code_size must // include both code and stubs sizes. CodeBuffer(const char* name, csize_t code_size, csize_t locs_size) { @@ -394,22 +410,22 @@ class CodeBuffer: public StackObj { ~CodeBuffer(); - // Initialize a CodeBuffer constructed using constructor 2. Using - // constructor 3 is equivalent to calling constructor 2 and then + // Initialize a CodeBuffer constructed using constructor 3. Using + // constructor 4 is equivalent to calling constructor 3 and then // calling this method. It's been factored out for convenience of // construction. void initialize(csize_t code_size, csize_t locs_size); + CodeSection* consts() { return &_consts; } CodeSection* insts() { return &_insts; } CodeSection* stubs() { return &_stubs; } - CodeSection* consts() { return &_consts; } - // present sections in order; return NULL at end; insts is #0, etc. + // present sections in order; return NULL at end; consts is #0, etc. CodeSection* code_section(int n) { - // This makes the slightly questionable but portable assumption that - // the various members (_insts, _stubs, etc.) are adjacent in the - // layout of CodeBuffer. - CodeSection* cs = &_insts + n; + // This makes the slightly questionable but portable assumption + // that the various members (_consts, _insts, _stubs, etc.) are + // adjacent in the layout of CodeBuffer. + CodeSection* cs = &_consts + n; assert(cs->index() == n || !cs->is_allocated(), "sanity"); return cs; } @@ -438,40 +454,41 @@ class CodeBuffer: public StackObj { void free_blob(); // Free the blob, if we own one. // Properties relative to the insts section: - address code_begin() const { return _insts.start(); } - address code_end() const { return _insts.end(); } - void set_code_end(address end) { _insts.set_end(end); } - address code_limit() const { return _insts.limit(); } - address inst_mark() const { return _insts.mark(); } - void set_inst_mark() { _insts.set_mark(); } - void clear_inst_mark() { _insts.clear_mark(); } + address insts_begin() const { return _insts.start(); } + address insts_end() const { return _insts.end(); } + void set_insts_end(address end) { _insts.set_end(end); } + address insts_limit() const { return _insts.limit(); } + address insts_mark() const { return _insts.mark(); } + void set_insts_mark() { _insts.set_mark(); } + void clear_insts_mark() { _insts.clear_mark(); } // is there anything in the buffer other than the current section? - bool is_pure() const { return code_size() == total_code_size(); } + bool is_pure() const { return insts_size() == total_content_size(); } // size in bytes of output so far in the insts sections - csize_t code_size() const { return _insts.size(); } + csize_t insts_size() const { return _insts.size(); } - // same as code_size(), except that it asserts there is no non-code here - csize_t pure_code_size() const { assert(is_pure(), "no non-code"); - return code_size(); } + // same as insts_size(), except that it asserts there is no non-code here + csize_t pure_insts_size() const { assert(is_pure(), "no non-code"); + return insts_size(); } // capacity in bytes of the insts sections - csize_t code_capacity() const { return _insts.capacity(); } + csize_t insts_capacity() const { return _insts.capacity(); } // number of bytes remaining in the insts section - csize_t code_remaining() const { return _insts.remaining(); } + csize_t insts_remaining() const { return _insts.remaining(); } // is a given address in the insts section? (2nd version is end-inclusive) - bool code_contains(address pc) const { return _insts.contains(pc); } - bool code_contains2(address pc) const { return _insts.contains2(pc); } + bool insts_contains(address pc) const { return _insts.contains(pc); } + bool insts_contains2(address pc) const { return _insts.contains2(pc); } - // allocated size of code in all sections, when aligned and concatenated - // (this is the eventual state of the code in its final CodeBlob) - csize_t total_code_size() const; + // Allocated size in all sections, when aligned and concatenated + // (this is the eventual state of the content in its final + // CodeBlob). + csize_t total_content_size() const; - // combined offset (relative to start of insts) of given address, - // as eventually found in the final CodeBlob - csize_t total_offset_of(address addr) const; + // Combined offset (relative to start of first section) of given + // section, as eventually found in the final CodeBlob. + csize_t total_offset_of(CodeSection* cs) const; // allocated size of all relocation data, including index, rounded up csize_t total_relocation_size() const; diff --git a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp index 5607fc00fa8..ec89b0edd06 100644 --- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp @@ -652,10 +652,20 @@ void Canonicalizer::do_If(If* x) { else if (lss_sux == gtr_sux) { cond = If::neq; tsux = lss_sux; fsux = eql_sux; } else if (eql_sux == gtr_sux) { cond = If::geq; tsux = eql_sux; fsux = lss_sux; } else { ShouldNotReachHere(); } - If* canon = new If(cmp->x(), cond, nan_sux == tsux, cmp->y(), tsux, fsux, cmp->state_before(), x->is_safepoint()); + If* canon = new If(cmp->x(), cond, nan_sux == tsux, cmp->y(), tsux, fsux, cmp->state_before(), x->is_safepoint()); if (cmp->x() == cmp->y()) { do_If(canon); } else { + if (compilation()->profile_branches()) { + // TODO: If profiling, leave floating point comparisons unoptimized. + // We currently do not support profiling of the unordered case. + switch(cmp->op()) { + case Bytecodes::_fcmpl: case Bytecodes::_fcmpg: + case Bytecodes::_dcmpl: case Bytecodes::_dcmpg: + set_canonical(x); + return; + } + } set_canonical(canon); set_bci(cmp->bci()); } @@ -663,6 +673,8 @@ void Canonicalizer::do_If(If* x) { } else if (l->as_InstanceOf() != NULL) { // NOTE: Code permanently disabled for now since it leaves the old InstanceOf // instruction in the graph (it is pinned). Need to fix this at some point. + // It should also be left in the graph when generating a profiled method version or Goto + // has to know that it was an InstanceOf. return; // pattern: If ((obj instanceof klass) cond rc) => simplify to: IfInstanceOf or: Goto InstanceOf* inst = l->as_InstanceOf(); @@ -881,4 +893,5 @@ void Canonicalizer::do_UnsafePutObject(UnsafePutObject* x) {} void Canonicalizer::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {} void Canonicalizer::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {} void Canonicalizer::do_ProfileCall(ProfileCall* x) {} -void Canonicalizer::do_ProfileCounter(ProfileCounter* x) {} +void Canonicalizer::do_ProfileInvoke(ProfileInvoke* x) {} + diff --git a/hotspot/src/share/vm/c1/c1_Canonicalizer.hpp b/hotspot/src/share/vm/c1/c1_Canonicalizer.hpp index ae2530c1011..a25a4bd238c 100644 --- a/hotspot/src/share/vm/c1/c1_Canonicalizer.hpp +++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,11 @@ class Canonicalizer: InstructionVisitor { private: + Compilation *_compilation; Instruction* _canonical; int _bci; + Compilation *compilation() { return _compilation; } void set_canonical(Value x); void set_bci(int bci) { _bci = bci; } void set_constant(jint x) { set_canonical(new Constant(new IntConstant(x))); } @@ -43,7 +45,9 @@ class Canonicalizer: InstructionVisitor { int* scale); public: - Canonicalizer(Value x, int bci) { _canonical = x; _bci = bci; if (CanonicalizeNodes) x->visit(this); } + Canonicalizer(Compilation* c, Value x, int bci) : _compilation(c), _canonical(x), _bci(bci) { + if (CanonicalizeNodes) x->visit(this); + } Value canonical() const { return _canonical; } int bci() const { return _bci; } @@ -92,5 +96,5 @@ class Canonicalizer: InstructionVisitor { virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x); virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); virtual void do_ProfileCall (ProfileCall* x); - virtual void do_ProfileCounter (ProfileCounter* x); + virtual void do_ProfileInvoke (ProfileInvoke* x); }; diff --git a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp index 07ed4302dd9..d8a8ed6bcb7 100644 --- a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp +++ b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp @@ -80,20 +80,21 @@ class CodeStubList: public _CodeStubList { } }; -#ifdef TIERED class CounterOverflowStub: public CodeStub { private: CodeEmitInfo* _info; int _bci; + LIR_Opr _method; public: - CounterOverflowStub(CodeEmitInfo* info, int bci) : _info(info), _bci(bci) { + CounterOverflowStub(CodeEmitInfo* info, int bci, LIR_Opr method) : _info(info), _bci(bci), _method(method) { } virtual void emit_code(LIR_Assembler* e); virtual void visit(LIR_OpVisitState* visitor) { visitor->do_slow_case(_info); + visitor->do_input(_method); } #ifndef PRODUCT @@ -101,7 +102,6 @@ public: #endif // PRODUCT }; -#endif // TIERED class ConversionStub: public CodeStub { private: diff --git a/hotspot/src/share/vm/c1/c1_Compilation.cpp b/hotspot/src/share/vm/c1/c1_Compilation.cpp index d9156c1b307..b1dd7e20158 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.cpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp @@ -290,9 +290,13 @@ int Compilation::compile_java_method() { CHECK_BAILOUT_(no_frame_size); + if (is_profiling()) { + method()->build_method_data(); + } + { PhaseTraceTime timeit(_t_buildIR); - build_hir(); + build_hir(); } if (BailoutAfterHIR) { BAILOUT_("Bailing out because of -XX:+BailoutAfterHIR", no_frame_size); @@ -447,6 +451,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho , _masm(NULL) , _has_exception_handlers(false) , _has_fpu_code(true) // pessimistic assumption +, _would_profile(false) , _has_unsafe_access(false) , _has_method_handle_invokes(false) , _bailout_msg(NULL) @@ -454,20 +459,23 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho , _allocator(NULL) , _next_id(0) , _next_block_id(0) -, _code(buffer_blob->instructions_begin(), - buffer_blob->instructions_size()) +, _code(buffer_blob) , _current_instruction(NULL) #ifndef PRODUCT , _last_instruction_printed(NULL) #endif // PRODUCT { PhaseTraceTime timeit(_t_compile); - _arena = Thread::current()->resource_area(); _env->set_compiler_data(this); _exception_info_list = new ExceptionInfoList(); _implicit_exception_table.set_size(0); compile_method(); + if (is_profiling() && _would_profile) { + ciMethodData *md = method->method_data(); + assert (md != NULL, "Should have MDO"); + md->set_would_profile(_would_profile); + } } Compilation::~Compilation() { diff --git a/hotspot/src/share/vm/c1/c1_Compilation.hpp b/hotspot/src/share/vm/c1/c1_Compilation.hpp index 82c1699ea91..a66db089173 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.hpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.hpp @@ -69,6 +69,7 @@ class Compilation: public StackObj { bool _has_exception_handlers; bool _has_fpu_code; bool _has_unsafe_access; + bool _would_profile; bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. const char* _bailout_msg; ExceptionInfoList* _exception_info_list; @@ -143,6 +144,7 @@ class Compilation: public StackObj { void set_has_exception_handlers(bool f) { _has_exception_handlers = f; } void set_has_fpu_code(bool f) { _has_fpu_code = f; } void set_has_unsafe_access(bool f) { _has_unsafe_access = f; } + void set_would_profile(bool f) { _would_profile = f; } // Add a set of exception handlers covering the given PC offset void add_exception_handlers_for_pco(int pco, XHandlers* exception_handlers); // Statistics gathering @@ -202,6 +204,30 @@ class Compilation: public StackObj { void compile_only_this_scope(outputStream* st, IRScope* scope); void exclude_this_method(); #endif // PRODUCT + + bool is_profiling() { + return env()->comp_level() == CompLevel_full_profile || + env()->comp_level() == CompLevel_limited_profile; + } + bool count_invocations() { return is_profiling(); } + bool count_backedges() { return is_profiling(); } + + // Helpers for generation of profile information + bool profile_branches() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && C1ProfileBranches; + } + bool profile_calls() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && C1ProfileCalls; + } + bool profile_inlined_calls() { + return profile_calls() && C1ProfileInlinedCalls; + } + bool profile_checkcasts() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && C1ProfileCheckcasts; + } }; diff --git a/hotspot/src/share/vm/c1/c1_Compiler.hpp b/hotspot/src/share/vm/c1/c1_Compiler.hpp index a8e6eacd748..43eb204f755 100644 --- a/hotspot/src/share/vm/c1/c1_Compiler.hpp +++ b/hotspot/src/share/vm/c1/c1_Compiler.hpp @@ -39,9 +39,7 @@ class Compiler: public AbstractCompiler { // Name of this compiler virtual const char* name() { return "C1"; } -#ifdef TIERED - virtual bool is_c1() { return true; }; -#endif // TIERED + virtual bool is_c1() { return true; }; BufferBlob* build_buffer_blob(); diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index 1e80c4598ff..5b7b7045aa2 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -967,6 +967,17 @@ void GraphBuilder::store_indexed(BasicType type) { StoreIndexed* result = new StoreIndexed(array, index, length, type, value, lock_stack()); append(result); _memory->store_value(value); + + if (type == T_OBJECT && is_profiling()) { + // Note that we'd collect profile data in this method if we wanted it. + compilation()->set_would_profile(true); + + if (profile_checkcasts()) { + result->set_profiled_method(method()); + result->set_profiled_bci(bci()); + result->set_should_profile(true); + } + } } @@ -1144,8 +1155,16 @@ void GraphBuilder::increment() { void GraphBuilder::_goto(int from_bci, int to_bci) { - profile_bci(from_bci); - append(new Goto(block_at(to_bci), to_bci <= from_bci)); + Goto *x = new Goto(block_at(to_bci), to_bci <= from_bci); + if (is_profiling()) { + compilation()->set_would_profile(true); + } + if (profile_branches()) { + x->set_profiled_method(method()); + x->set_profiled_bci(bci()); + x->set_should_profile(true); + } + append(x); } @@ -1153,11 +1172,45 @@ void GraphBuilder::if_node(Value x, If::Condition cond, Value y, ValueStack* sta BlockBegin* tsux = block_at(stream()->get_dest()); BlockBegin* fsux = block_at(stream()->next_bci()); bool is_bb = tsux->bci() < stream()->cur_bci() || fsux->bci() < stream()->cur_bci(); - If* if_node = append(new If(x, cond, false, y, tsux, fsux, is_bb ? state_before : NULL, is_bb))->as_If(); - if (profile_branches() && (if_node != NULL)) { - if_node->set_profiled_method(method()); - if_node->set_profiled_bci(bci()); - if_node->set_should_profile(true); + Instruction *i = append(new If(x, cond, false, y, tsux, fsux, is_bb ? state_before : NULL, is_bb)); + + if (is_profiling()) { + If* if_node = i->as_If(); + if (if_node != NULL) { + // Note that we'd collect profile data in this method if we wanted it. + compilation()->set_would_profile(true); + // At level 2 we need the proper bci to count backedges + if_node->set_profiled_bci(bci()); + if (profile_branches()) { + // Successors can be rotated by the canonicalizer, check for this case. + if_node->set_profiled_method(method()); + if_node->set_should_profile(true); + if (if_node->tsux() == fsux) { + if_node->set_swapped(true); + } + } + return; + } + + // Check if this If was reduced to Goto. + Goto *goto_node = i->as_Goto(); + if (goto_node != NULL) { + compilation()->set_would_profile(true); + if (profile_branches()) { + goto_node->set_profiled_method(method()); + goto_node->set_profiled_bci(bci()); + goto_node->set_should_profile(true); + // Find out which successor is used. + if (goto_node->default_sux() == tsux) { + goto_node->set_direction(Goto::taken); + } else if (goto_node->default_sux() == fsux) { + goto_node->set_direction(Goto::not_taken); + } else { + ShouldNotReachHere(); + } + } + return; + } } } @@ -1698,8 +1751,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) { if (recv != NULL && (code == Bytecodes::_invokespecial || - !is_loaded || target->is_final() || - profile_calls())) { + !is_loaded || target->is_final())) { // invokespecial always needs a NULL check. invokevirtual where // the target is final or where it's not known that whether the // target is final requires a NULL check. Otherwise normal @@ -1709,15 +1761,23 @@ void GraphBuilder::invoke(Bytecodes::Code code) { null_check(recv); } - if (profile_calls()) { - assert(cha_monomorphic_target == NULL || exact_target == NULL, "both can not be set"); - ciKlass* target_klass = NULL; - if (cha_monomorphic_target != NULL) { - target_klass = cha_monomorphic_target->holder(); - } else if (exact_target != NULL) { - target_klass = exact_target->holder(); + if (is_profiling()) { + if (recv != NULL && profile_calls()) { + null_check(recv); + } + // Note that we'd collect profile data in this method if we wanted it. + compilation()->set_would_profile(true); + + if (profile_calls()) { + assert(cha_monomorphic_target == NULL || exact_target == NULL, "both can not be set"); + ciKlass* target_klass = NULL; + if (cha_monomorphic_target != NULL) { + target_klass = cha_monomorphic_target->holder(); + } else if (exact_target != NULL) { + target_klass = exact_target->holder(); + } + profile_call(recv, target_klass); } - profile_call(recv, target_klass); } Invoke* result = new Invoke(code, result_type, recv, args, vtable_index, target, state_before); @@ -1782,10 +1842,16 @@ void GraphBuilder::check_cast(int klass_index) { CheckCast* c = new CheckCast(klass, apop(), state_before); apush(append_split(c)); c->set_direct_compare(direct_compare(klass)); - if (profile_checkcasts()) { - c->set_profiled_method(method()); - c->set_profiled_bci(bci()); - c->set_should_profile(true); + + if (is_profiling()) { + // Note that we'd collect profile data in this method if we wanted it. + compilation()->set_would_profile(true); + + if (profile_checkcasts()) { + c->set_profiled_method(method()); + c->set_profiled_bci(bci()); + c->set_should_profile(true); + } } } @@ -1797,6 +1863,17 @@ void GraphBuilder::instance_of(int klass_index) { InstanceOf* i = new InstanceOf(klass, apop(), state_before); ipush(append_split(i)); i->set_direct_compare(direct_compare(klass)); + + if (is_profiling()) { + // Note that we'd collect profile data in this method if we wanted it. + compilation()->set_would_profile(true); + + if (profile_checkcasts()) { + i->set_profiled_method(method()); + i->set_profiled_bci(bci()); + i->set_should_profile(true); + } + } } @@ -1868,7 +1945,7 @@ Value GraphBuilder::round_fp(Value fp_value) { Instruction* GraphBuilder::append_with_bci(Instruction* instr, int bci) { - Canonicalizer canon(instr, bci); + Canonicalizer canon(compilation(), instr, bci); Instruction* i1 = canon.canonical(); if (i1->bci() != -99) { // Canonicalizer returned an instruction which was already @@ -2651,18 +2728,6 @@ BlockBegin* GraphBuilder::header_block(BlockBegin* entry, BlockBegin::Flag f, Va h->set_depth_first_number(0); Value l = h; - if (profile_branches()) { - // Increment the invocation count on entry to the method. We - // can't use profile_invocation here because append isn't setup to - // work properly at this point. The instruction have to be - // appended to the instruction stream by hand. - Value m = new Constant(new ObjectConstant(compilation()->method())); - h->set_next(m, 0); - Value p = new ProfileCounter(m, methodOopDesc::interpreter_invocation_counter_offset_in_bytes(), 1); - m->set_next(p, 0); - l = p; - } - BlockEnd* g = new Goto(entry, false); l->set_next(g, entry->bci()); h->set_end(g); @@ -2688,10 +2753,10 @@ BlockBegin* GraphBuilder::setup_start_block(int osr_bci, BlockBegin* std_entry, // also necessary when profiling so that there's a single block that // can increment the interpreter_invocation_count. BlockBegin* new_header_block; - if (std_entry->number_of_preds() == 0 && !profile_branches()) { - new_header_block = std_entry; - } else { + if (std_entry->number_of_preds() > 0 || count_invocations() || count_backedges()) { new_header_block = header_block(std_entry, BlockBegin::std_entry_flag, state); + } else { + new_header_block = std_entry; } // setup start block (root for the IR graph) @@ -3115,16 +3180,21 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { Values* args = state()->pop_arguments(callee->arg_size()); ValueStack* locks = lock_stack(); - if (profile_calls()) { + + if (is_profiling()) { // Don't profile in the special case where the root method // is the intrinsic if (callee != method()) { - Value recv = NULL; - if (has_receiver) { - recv = args->at(0); - null_check(recv); + // Note that we'd collect profile data in this method if we wanted it. + compilation()->set_would_profile(true); + if (profile_calls()) { + Value recv = NULL; + if (has_receiver) { + recv = args->at(0); + null_check(recv); + } + profile_call(recv, NULL); } - profile_call(recv, NULL); } } @@ -3296,7 +3366,9 @@ void GraphBuilder::fill_sync_handler(Value lock, BlockBegin* sync_handler, bool bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known) { assert(!callee->is_native(), "callee must not be native"); - + if (count_backedges() && callee->has_loops()) { + INLINE_BAILOUT("too complex for tiered"); + } // first perform tests of things it's not possible to inline if (callee->has_exception_handlers() && !InlineMethodsWithExceptionHandlers) INLINE_BAILOUT("callee has exception handlers"); @@ -3365,11 +3437,18 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known) { null_check(recv); } - if (profile_inlined_calls()) { - profile_call(recv, holder_known ? callee->holder() : NULL); - } + if (is_profiling()) { + // Note that we'd collect profile data in this method if we wanted it. + // this may be redundant here... + compilation()->set_would_profile(true); - profile_invocation(callee); + if (profile_calls()) { + profile_call(recv, holder_known ? callee->holder() : NULL); + } + if (profile_inlined_calls()) { + profile_invocation(callee, state(), 0); + } + } // Introduce a new callee continuation point - if the callee has // more than one return instruction or the return does not allow @@ -3755,30 +3834,10 @@ void GraphBuilder::print_stats() { } #endif // PRODUCT - void GraphBuilder::profile_call(Value recv, ciKlass* known_holder) { append(new ProfileCall(method(), bci(), recv, known_holder)); } - -void GraphBuilder::profile_invocation(ciMethod* callee) { - if (profile_calls()) { - // increment the interpreter_invocation_count for the inlinee - Value m = append(new Constant(new ObjectConstant(callee))); - append(new ProfileCounter(m, methodOopDesc::interpreter_invocation_counter_offset_in_bytes(), 1)); - } -} - - -void GraphBuilder::profile_bci(int bci) { - if (profile_branches()) { - ciMethodData* md = method()->method_data(); - if (md == NULL) { - BAILOUT("out of memory building methodDataOop"); - } - ciProfileData* data = md->bci_to_data(bci); - assert(data != NULL && data->is_JumpData(), "need JumpData for goto"); - Value mdo = append(new Constant(new ObjectConstant(md))); - append(new ProfileCounter(mdo, md->byte_offset_of_slot(data, JumpData::taken_offset()), 1)); - } +void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state, int bci) { + append(new ProfileInvoke(callee, state, bci)); } diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp index 4ce9dd2bdf3..1a6c6f28d22 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -342,27 +342,17 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC { NOT_PRODUCT(void print_inline_result(ciMethod* callee, bool res);) - // methodDataOop profiling helpers void profile_call(Value recv, ciKlass* predicted_holder); - void profile_invocation(ciMethod* method); - void profile_bci(int bci); + void profile_invocation(ciMethod* inlinee, ValueStack* state, int bci); - // Helpers for generation of profile information - bool profile_branches() { - return _compilation->env()->comp_level() == CompLevel_fast_compile && - Tier1UpdateMethodData && Tier1ProfileBranches; - } - bool profile_calls() { - return _compilation->env()->comp_level() == CompLevel_fast_compile && - Tier1UpdateMethodData && Tier1ProfileCalls; - } - bool profile_inlined_calls() { - return profile_calls() && Tier1ProfileInlinedCalls; - } - bool profile_checkcasts() { - return _compilation->env()->comp_level() == CompLevel_fast_compile && - Tier1UpdateMethodData && Tier1ProfileCheckcasts; - } + // Shortcuts to profiling control. + bool is_profiling() { return _compilation->is_profiling(); } + bool count_invocations() { return _compilation->count_invocations(); } + bool count_backedges() { return _compilation->count_backedges(); } + bool profile_branches() { return _compilation->profile_branches(); } + bool profile_calls() { return _compilation->profile_calls(); } + bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); } + bool profile_checkcasts() { return _compilation->profile_checkcasts(); } public: NOT_PRODUCT(void print_stats();) diff --git a/hotspot/src/share/vm/c1/c1_IR.cpp b/hotspot/src/share/vm/c1/c1_IR.cpp index 4df75f40f66..cb5e2098ece 100644 --- a/hotspot/src/share/vm/c1/c1_IR.cpp +++ b/hotspot/src/share/vm/c1/c1_IR.cpp @@ -296,19 +296,21 @@ IR::IR(Compilation* compilation, ciMethod* method, int osr_bci) : void IR::optimize() { Optimizer opt(this); - if (DoCEE) { - opt.eliminate_conditional_expressions(); + if (!compilation()->profile_branches()) { + if (DoCEE) { + opt.eliminate_conditional_expressions(); #ifndef PRODUCT - if (PrintCFG || PrintCFG1) { tty->print_cr("CFG after CEE"); print(true); } - if (PrintIR || PrintIR1 ) { tty->print_cr("IR after CEE"); print(false); } + if (PrintCFG || PrintCFG1) { tty->print_cr("CFG after CEE"); print(true); } + if (PrintIR || PrintIR1 ) { tty->print_cr("IR after CEE"); print(false); } #endif - } - if (EliminateBlocks) { - opt.eliminate_blocks(); + } + if (EliminateBlocks) { + opt.eliminate_blocks(); #ifndef PRODUCT - if (PrintCFG || PrintCFG1) { tty->print_cr("CFG after block elimination"); print(true); } - if (PrintIR || PrintIR1 ) { tty->print_cr("IR after block elimination"); print(false); } + if (PrintCFG || PrintCFG1) { tty->print_cr("CFG after block elimination"); print(true); } + if (PrintIR || PrintIR1 ) { tty->print_cr("IR after block elimination"); print(false); } #endif + } } if (EliminateNullChecks) { opt.eliminate_null_checks(); @@ -484,6 +486,8 @@ class ComputeLinearScanOrder : public StackObj { BitMap2D _loop_map; // two-dimensional bit set: a bit is set if a block is contained in a loop BlockList _work_list; // temporary list (used in mark_loops and compute_order) + Compilation* _compilation; + // accessors for _visited_blocks and _active_blocks void init_visited() { _active_blocks.clear(); _visited_blocks.clear(); } bool is_visited(BlockBegin* b) const { return _visited_blocks.at(b->block_id()); } @@ -526,8 +530,9 @@ class ComputeLinearScanOrder : public StackObj { NOT_PRODUCT(void print_blocks();) DEBUG_ONLY(void verify();) + Compilation* compilation() const { return _compilation; } public: - ComputeLinearScanOrder(BlockBegin* start_block); + ComputeLinearScanOrder(Compilation* c, BlockBegin* start_block); // accessors for final result BlockList* linear_scan_order() const { return _linear_scan_order; } @@ -535,7 +540,7 @@ class ComputeLinearScanOrder : public StackObj { }; -ComputeLinearScanOrder::ComputeLinearScanOrder(BlockBegin* start_block) : +ComputeLinearScanOrder::ComputeLinearScanOrder(Compilation* c, BlockBegin* start_block) : _max_block_id(BlockBegin::number_of_blocks()), _num_blocks(0), _num_loops(0), @@ -547,13 +552,18 @@ ComputeLinearScanOrder::ComputeLinearScanOrder(BlockBegin* start_block) : _loop_end_blocks(8), _work_list(8), _linear_scan_order(NULL), // initialized later with correct size - _loop_map(0, 0) // initialized later with correct size + _loop_map(0, 0), // initialized later with correct size + _compilation(c) { TRACE_LINEAR_SCAN(2, "***** computing linear-scan block order"); init_visited(); count_edges(start_block, NULL); + if (compilation()->is_profiling()) { + compilation()->method()->method_data()->set_compilation_stats(_num_loops, _num_blocks); + } + if (_num_loops > 0) { mark_loops(); clear_non_natural_loops(start_block); @@ -1130,7 +1140,7 @@ void ComputeLinearScanOrder::verify() { void IR::compute_code() { assert(is_valid(), "IR must be valid"); - ComputeLinearScanOrder compute_order(start()); + ComputeLinearScanOrder compute_order(compilation(), start()); _num_loops = compute_order.num_loops(); _code = compute_order.linear_scan_order(); } diff --git a/hotspot/src/share/vm/c1/c1_Instruction.cpp b/hotspot/src/share/vm/c1/c1_Instruction.cpp index 018047a3519..e0728b2f304 100644 --- a/hotspot/src/share/vm/c1/c1_Instruction.cpp +++ b/hotspot/src/share/vm/c1/c1_Instruction.cpp @@ -740,9 +740,9 @@ void BlockBegin::block_values_do(ValueVisitor* f) { #ifndef PRODUCT - #define TRACE_PHI(code) if (PrintPhiFunctions) { code; } + #define TRACE_PHI(code) if (PrintPhiFunctions) { code; } #else - #define TRACE_PHI(coce) + #define TRACE_PHI(coce) #endif @@ -1011,3 +1011,7 @@ int Phi::operand_count() const { void Throw::state_values_do(ValueVisitor* f) { BlockEnd::state_values_do(f); } + +void ProfileInvoke::state_values_do(ValueVisitor* f) { + if (state() != NULL) state()->values_do(f); +} diff --git a/hotspot/src/share/vm/c1/c1_Instruction.hpp b/hotspot/src/share/vm/c1/c1_Instruction.hpp index 98e9d41bc8a..52b2f84a76f 100644 --- a/hotspot/src/share/vm/c1/c1_Instruction.hpp +++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp @@ -98,7 +98,7 @@ class UnsafePrefetch; class UnsafePrefetchRead; class UnsafePrefetchWrite; class ProfileCall; -class ProfileCounter; +class ProfileInvoke; // A Value is a reference to the instruction creating the value typedef Instruction* Value; @@ -195,7 +195,7 @@ class InstructionVisitor: public StackObj { virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x) = 0; virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) = 0; virtual void do_ProfileCall (ProfileCall* x) = 0; - virtual void do_ProfileCounter (ProfileCounter* x) = 0; + virtual void do_ProfileInvoke (ProfileInvoke* x) = 0; }; @@ -906,11 +906,13 @@ LEAF(StoreIndexed, AccessIndexed) private: Value _value; + ciMethod* _profiled_method; + int _profiled_bci; public: // creation StoreIndexed(Value array, Value index, Value length, BasicType elt_type, Value value, ValueStack* lock_stack) : AccessIndexed(array, index, length, elt_type, lock_stack) - , _value(value) + , _value(value), _profiled_method(NULL), _profiled_bci(0) { set_flag(NeedsWriteBarrierFlag, (as_ValueType(elt_type)->is_object())); set_flag(NeedsStoreCheckFlag, (as_ValueType(elt_type)->is_object())); @@ -923,7 +925,13 @@ LEAF(StoreIndexed, AccessIndexed) IRScope* scope() const; // the state's scope bool needs_write_barrier() const { return check_flag(NeedsWriteBarrierFlag); } bool needs_store_check() const { return check_flag(NeedsStoreCheckFlag); } - + // Helpers for methodDataOop profiling + void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } + void set_profiled_method(ciMethod* method) { _profiled_method = method; } + void set_profiled_bci(int bci) { _profiled_bci = bci; } + bool should_profile() const { return check_flag(ProfileMDOFlag); } + ciMethod* profiled_method() const { return _profiled_method; } + int profiled_bci() const { return _profiled_bci; } // generic virtual void input_values_do(ValueVisitor* f) { AccessIndexed::input_values_do(f); f->visit(&_value); } }; @@ -1297,9 +1305,14 @@ BASE(TypeCheck, StateSplit) Value _obj; ValueStack* _state_before; + ciMethod* _profiled_method; + int _profiled_bci; + public: // creation - TypeCheck(ciKlass* klass, Value obj, ValueType* type, ValueStack* state_before) : StateSplit(type), _klass(klass), _obj(obj), _state_before(state_before) { + TypeCheck(ciKlass* klass, Value obj, ValueType* type, ValueStack* state_before) + : StateSplit(type), _klass(klass), _obj(obj), _state_before(state_before), + _profiled_method(NULL), _profiled_bci(0) { ASSERT_VALUES set_direct_compare(false); } @@ -1318,27 +1331,6 @@ BASE(TypeCheck, StateSplit) virtual bool can_trap() const { return true; } virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_obj); } virtual void other_values_do(ValueVisitor* f); -}; - - -LEAF(CheckCast, TypeCheck) - private: - ciMethod* _profiled_method; - int _profiled_bci; - - public: - // creation - CheckCast(ciKlass* klass, Value obj, ValueStack* state_before) - : TypeCheck(klass, obj, objectType, state_before) - , _profiled_method(NULL) - , _profiled_bci(0) {} - - void set_incompatible_class_change_check() { - set_flag(ThrowIncompatibleClassChangeErrorFlag, true); - } - bool is_incompatible_class_change_check() const { - return check_flag(ThrowIncompatibleClassChangeErrorFlag); - } // Helpers for methodDataOop profiling void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } @@ -1347,10 +1339,24 @@ LEAF(CheckCast, TypeCheck) bool should_profile() const { return check_flag(ProfileMDOFlag); } ciMethod* profiled_method() const { return _profiled_method; } int profiled_bci() const { return _profiled_bci; } +}; + + +LEAF(CheckCast, TypeCheck) + public: + // creation + CheckCast(ciKlass* klass, Value obj, ValueStack* state_before) + : TypeCheck(klass, obj, objectType, state_before) {} + + void set_incompatible_class_change_check() { + set_flag(ThrowIncompatibleClassChangeErrorFlag, true); + } + bool is_incompatible_class_change_check() const { + return check_flag(ThrowIncompatibleClassChangeErrorFlag); + } ciType* declared_type() const; ciType* exact_type() const; - }; @@ -1733,20 +1739,45 @@ BASE(BlockEnd, StateSplit) LEAF(Goto, BlockEnd) + public: + enum Direction { + none, // Just a regular goto + taken, not_taken // Goto produced from If + }; + private: + ciMethod* _profiled_method; + int _profiled_bci; + Direction _direction; public: // creation - Goto(BlockBegin* sux, ValueStack* state_before, bool is_safepoint = false) : BlockEnd(illegalType, state_before, is_safepoint) { + Goto(BlockBegin* sux, ValueStack* state_before, bool is_safepoint = false) + : BlockEnd(illegalType, state_before, is_safepoint) + , _direction(none) + , _profiled_method(NULL) + , _profiled_bci(0) { BlockList* s = new BlockList(1); s->append(sux); set_sux(s); } - Goto(BlockBegin* sux, bool is_safepoint) : BlockEnd(illegalType, NULL, is_safepoint) { + Goto(BlockBegin* sux, bool is_safepoint) : BlockEnd(illegalType, NULL, is_safepoint) + , _direction(none) + , _profiled_method(NULL) + , _profiled_bci(0) { BlockList* s = new BlockList(1); s->append(sux); set_sux(s); } + bool should_profile() const { return check_flag(ProfileMDOFlag); } + ciMethod* profiled_method() const { return _profiled_method; } // set only for profiled branches + int profiled_bci() const { return _profiled_bci; } + Direction direction() const { return _direction; } + + void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } + void set_profiled_method(ciMethod* method) { _profiled_method = method; } + void set_profiled_bci(int bci) { _profiled_bci = bci; } + void set_direction(Direction d) { _direction = d; } }; @@ -1757,6 +1788,8 @@ LEAF(If, BlockEnd) Value _y; ciMethod* _profiled_method; int _profiled_bci; // Canonicalizer may alter bci of If node + bool _swapped; // Is the order reversed with respect to the original If in the + // bytecode stream? public: // creation // unordered_is_true is valid for float/double compares only @@ -1767,6 +1800,7 @@ LEAF(If, BlockEnd) , _y(y) , _profiled_method(NULL) , _profiled_bci(0) + , _swapped(false) { ASSERT_VALUES set_flag(UnorderedIsTrueFlag, unordered_is_true); @@ -1788,7 +1822,8 @@ LEAF(If, BlockEnd) BlockBegin* usux() const { return sux_for(unordered_is_true()); } bool should_profile() const { return check_flag(ProfileMDOFlag); } ciMethod* profiled_method() const { return _profiled_method; } // set only for profiled branches - int profiled_bci() const { return _profiled_bci; } // set only for profiled branches + int profiled_bci() const { return _profiled_bci; } // set for profiled branches and tiered + bool is_swapped() const { return _swapped; } // manipulation void swap_operands() { @@ -1807,7 +1842,7 @@ LEAF(If, BlockEnd) void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } void set_profiled_method(ciMethod* method) { _profiled_method = method; } void set_profiled_bci(int bci) { _profiled_bci = bci; } - + void set_swapped(bool value) { _swapped = value; } // generic virtual void input_values_do(ValueVisitor* f) { BlockEnd::input_values_do(f); f->visit(&_x); f->visit(&_y); } }; @@ -2235,7 +2270,6 @@ LEAF(UnsafePrefetchWrite, UnsafePrefetch) } }; - LEAF(ProfileCall, Instruction) private: ciMethod* _method; @@ -2263,35 +2297,32 @@ LEAF(ProfileCall, Instruction) virtual void input_values_do(ValueVisitor* f) { if (_recv != NULL) f->visit(&_recv); } }; +// Use to trip invocation counter of an inlined method -// -// Simple node representing a counter update generally used for updating MDOs -// -LEAF(ProfileCounter, Instruction) +LEAF(ProfileInvoke, Instruction) private: - Value _mdo; - int _offset; - int _increment; + ciMethod* _inlinee; + ValueStack* _state; + int _bci_of_invoke; public: - ProfileCounter(Value mdo, int offset, int increment = 1) + ProfileInvoke(ciMethod* inlinee, ValueStack* state, int bci) : Instruction(voidType) - , _mdo(mdo) - , _offset(offset) - , _increment(increment) + , _inlinee(inlinee) + , _bci_of_invoke(bci) + , _state(state) { - // The ProfileCounter has side-effects and must occur precisely where located + // The ProfileInvoke has side-effects and must occur precisely where located QQQ??? pin(); } - Value mdo() { return _mdo; } - int offset() { return _offset; } - int increment() { return _increment; } - - virtual void input_values_do(ValueVisitor* f) { f->visit(&_mdo); } + ciMethod* inlinee() { return _inlinee; } + ValueStack* state() { return _state; } + int bci_of_invoke() { return _bci_of_invoke; } + virtual void input_values_do(ValueVisitor*) {} + virtual void state_values_do(ValueVisitor*); }; - class BlockPair: public CompilationResourceObj { private: BlockBegin* _from; diff --git a/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp b/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp index fa473b16170..84e7b6fb897 100644 --- a/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp +++ b/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -819,7 +819,6 @@ void InstructionPrinter::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { output()->put(')'); } - void InstructionPrinter::do_ProfileCall(ProfileCall* x) { output()->print("profile "); print_value(x->recv()); @@ -831,20 +830,11 @@ void InstructionPrinter::do_ProfileCall(ProfileCall* x) { output()->put(')'); } +void InstructionPrinter::do_ProfileInvoke(ProfileInvoke* x) { + output()->print("profile_invoke "); + output()->print(" %s.%s", x->inlinee()->holder()->name()->as_utf8(), x->inlinee()->name()->as_utf8()); + output()->put(')'); -void InstructionPrinter::do_ProfileCounter(ProfileCounter* x) { - - ObjectConstant* oc = x->mdo()->type()->as_ObjectConstant(); - if (oc != NULL && oc->value()->is_method() && - x->offset() == methodOopDesc::interpreter_invocation_counter_offset_in_bytes()) { - print_value(x->mdo()); - output()->print(".interpreter_invocation_count += %d", x->increment()); - } else { - output()->print("counter ["); - print_value(x->mdo()); - output()->print(" + %d] += %d", x->offset(), x->increment()); - } } - #endif // PRODUCT diff --git a/hotspot/src/share/vm/c1/c1_InstructionPrinter.hpp b/hotspot/src/share/vm/c1/c1_InstructionPrinter.hpp index 7599abc077b..340c16237b5 100644 --- a/hotspot/src/share/vm/c1/c1_InstructionPrinter.hpp +++ b/hotspot/src/share/vm/c1/c1_InstructionPrinter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,6 +123,6 @@ class InstructionPrinter: public InstructionVisitor { virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x); virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); virtual void do_ProfileCall (ProfileCall* x); - virtual void do_ProfileCounter (ProfileCounter* x); + virtual void do_ProfileInvoke (ProfileInvoke* x); }; #endif // PRODUCT diff --git a/hotspot/src/share/vm/c1/c1_LIR.cpp b/hotspot/src/share/vm/c1/c1_LIR.cpp index a55ed09fc49..3b04fc45dc5 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.cpp +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp @@ -345,9 +345,8 @@ void LIR_OpBranch::negate_cond() { LIR_OpTypeCheck::LIR_OpTypeCheck(LIR_Code code, LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_exception, CodeEmitInfo* info_for_patch, - CodeStub* stub, - ciMethod* profiled_method, - int profiled_bci) + CodeStub* stub) + : LIR_Op(code, result, NULL) , _object(object) , _array(LIR_OprFact::illegalOpr) @@ -359,8 +358,10 @@ LIR_OpTypeCheck::LIR_OpTypeCheck(LIR_Code code, LIR_Opr result, LIR_Opr object, , _stub(stub) , _info_for_patch(info_for_patch) , _info_for_exception(info_for_exception) - , _profiled_method(profiled_method) - , _profiled_bci(profiled_bci) { + , _profiled_method(NULL) + , _profiled_bci(-1) + , _should_profile(false) +{ if (code == lir_checkcast) { assert(info_for_exception != NULL, "checkcast throws exceptions"); } else if (code == lir_instanceof) { @@ -372,7 +373,7 @@ LIR_OpTypeCheck::LIR_OpTypeCheck(LIR_Code code, LIR_Opr result, LIR_Opr object, -LIR_OpTypeCheck::LIR_OpTypeCheck(LIR_Code code, LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception, ciMethod* profiled_method, int profiled_bci) +LIR_OpTypeCheck::LIR_OpTypeCheck(LIR_Code code, LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception) : LIR_Op(code, LIR_OprFact::illegalOpr, NULL) , _object(object) , _array(array) @@ -384,8 +385,10 @@ LIR_OpTypeCheck::LIR_OpTypeCheck(LIR_Code code, LIR_Opr object, LIR_Opr array, L , _stub(NULL) , _info_for_patch(NULL) , _info_for_exception(info_for_exception) - , _profiled_method(profiled_method) - , _profiled_bci(profiled_bci) { + , _profiled_method(NULL) + , _profiled_bci(-1) + , _should_profile(false) +{ if (code == lir_store_check) { _stub = new ArrayStoreExceptionStub(info_for_exception); assert(info_for_exception != NULL, "store_check throws exceptions"); @@ -495,6 +498,8 @@ void LIR_OpVisitState::visit(LIR_Op* op) { case lir_monaddr: // input and result always valid, info always invalid case lir_null_check: // input and info always valid, result always invalid case lir_move: // input and result always valid, may have info + case lir_pack64: // input and result always valid + case lir_unpack64: // input and result always valid case lir_prefetchr: // input always valid, result and info always invalid case lir_prefetchw: // input always valid, result and info always invalid { @@ -903,7 +908,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) { assert(opProfileCall->_tmp1->is_valid(), "used"); do_temp(opProfileCall->_tmp1); break; } - default: ShouldNotReachHere(); } @@ -1041,12 +1045,10 @@ void LIR_OpDelay::emit_code(LIR_Assembler* masm) { masm->emit_delay(this); } - void LIR_OpProfileCall::emit_code(LIR_Assembler* masm) { masm->emit_profile_call(this); } - // LIR_List LIR_List::LIR_List(Compilation* compilation, BlockBegin* block) : _operations(8) @@ -1364,19 +1366,29 @@ void LIR_List::checkcast (LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_exception, CodeEmitInfo* info_for_patch, CodeStub* stub, ciMethod* profiled_method, int profiled_bci) { - append(new LIR_OpTypeCheck(lir_checkcast, result, object, klass, - tmp1, tmp2, tmp3, fast_check, info_for_exception, info_for_patch, stub, - profiled_method, profiled_bci)); + LIR_OpTypeCheck* c = new LIR_OpTypeCheck(lir_checkcast, result, object, klass, + tmp1, tmp2, tmp3, fast_check, info_for_exception, info_for_patch, stub); + if (profiled_method != NULL) { + c->set_profiled_method(profiled_method); + c->set_profiled_bci(profiled_bci); + c->set_should_profile(true); + } + append(c); } - -void LIR_List::instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch) { - append(new LIR_OpTypeCheck(lir_instanceof, result, object, klass, tmp1, tmp2, tmp3, fast_check, NULL, info_for_patch, NULL, NULL, 0)); +void LIR_List::instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch, ciMethod* profiled_method, int profiled_bci) { + LIR_OpTypeCheck* c = new LIR_OpTypeCheck(lir_instanceof, result, object, klass, tmp1, tmp2, tmp3, fast_check, NULL, info_for_patch, NULL); + if (profiled_method != NULL) { + c->set_profiled_method(profiled_method); + c->set_profiled_bci(profiled_bci); + c->set_should_profile(true); + } + append(c); } void LIR_List::store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception) { - append(new LIR_OpTypeCheck(lir_store_check, object, array, tmp1, tmp2, tmp3, info_for_exception, NULL, 0)); + append(new LIR_OpTypeCheck(lir_store_check, object, array, tmp1, tmp2, tmp3, info_for_exception)); } @@ -1611,6 +1623,8 @@ const char * LIR_Op::name() const { case lir_convert: s = "convert"; break; case lir_alloc_object: s = "alloc_obj"; break; case lir_monaddr: s = "mon_addr"; break; + case lir_pack64: s = "pack64"; break; + case lir_unpack64: s = "unpack64"; break; // LIR_Op2 case lir_cmp: s = "cmp"; break; case lir_cmp_l2i: s = "cmp_l2i"; break; @@ -1664,7 +1678,6 @@ const char * LIR_Op::name() const { case lir_cas_int: s = "cas_int"; break; // LIR_OpProfileCall case lir_profile_call: s = "profile_call"; break; - case lir_none: ShouldNotReachHere();break; default: s = "illegal_op"; break; } @@ -1922,7 +1935,6 @@ void LIR_OpProfileCall::print_instr(outputStream* out) const { tmp1()->print(out); out->print(" "); } - #endif // PRODUCT // Implementation of LIR_InsertionBuffer diff --git a/hotspot/src/share/vm/c1/c1_LIR.hpp b/hotspot/src/share/vm/c1/c1_LIR.hpp index 5c7dc4feb07..44393aa8fb3 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.hpp +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp @@ -849,6 +849,8 @@ enum LIR_Code { , lir_monaddr , lir_roundfp , lir_safepoint + , lir_pack64 + , lir_unpack64 , lir_unwind , end_op1 , begin_op2 @@ -1464,18 +1466,16 @@ class LIR_OpTypeCheck: public LIR_Op { CodeEmitInfo* _info_for_patch; CodeEmitInfo* _info_for_exception; CodeStub* _stub; - // Helpers for Tier1UpdateMethodData ciMethod* _profiled_method; int _profiled_bci; + bool _should_profile; public: LIR_OpTypeCheck(LIR_Code code, LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, - CodeEmitInfo* info_for_exception, CodeEmitInfo* info_for_patch, CodeStub* stub, - ciMethod* profiled_method, int profiled_bci); + CodeEmitInfo* info_for_exception, CodeEmitInfo* info_for_patch, CodeStub* stub); LIR_OpTypeCheck(LIR_Code code, LIR_Opr object, LIR_Opr array, - LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception, - ciMethod* profiled_method, int profiled_bci); + LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception); LIR_Opr object() const { return _object; } LIR_Opr array() const { assert(code() == lir_store_check, "not valid"); return _array; } @@ -1489,8 +1489,12 @@ public: CodeStub* stub() const { return _stub; } // methodDataOop profiling - ciMethod* profiled_method() { return _profiled_method; } - int profiled_bci() { return _profiled_bci; } + void set_profiled_method(ciMethod *method) { _profiled_method = method; } + void set_profiled_bci(int bci) { _profiled_bci = bci; } + void set_should_profile(bool b) { _should_profile = b; } + ciMethod* profiled_method() const { return _profiled_method; } + int profiled_bci() const { return _profiled_bci; } + bool should_profile() const { return _should_profile; } virtual void emit_code(LIR_Assembler* masm); virtual LIR_OpTypeCheck* as_OpTypeCheck() { return this; } @@ -1771,7 +1775,6 @@ class LIR_OpProfileCall : public LIR_Op { virtual void print_instr(outputStream* out) const PRODUCT_RETURN; }; - class LIR_InsertionBuffer; //--------------------------------LIR_List--------------------------------------------------- @@ -1835,6 +1838,7 @@ class LIR_List: public CompilationResourceObj { //---------- mutators --------------- void insert_before(int i, LIR_List* op_list) { _operations.insert_before(i, op_list->instructions_list()); } void insert_before(int i, LIR_Op* op) { _operations.insert_before(i, op); } + void remove_at(int i) { _operations.remove_at(i); } //---------- printing ------------- void print_instructions() PRODUCT_RETURN; @@ -1908,6 +1912,9 @@ class LIR_List: public CompilationResourceObj { void logical_or (LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_logic_or, left, right, dst)); } void logical_xor (LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_logic_xor, left, right, dst)); } + void pack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_pack64, src, dst, T_LONG, lir_patch_none, NULL)); } + void unpack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_unpack64, src, dst, T_LONG, lir_patch_none, NULL)); } + void null_check(LIR_Opr opr, CodeEmitInfo* info) { append(new LIR_Op1(lir_null_check, opr, info)); } void throw_exception(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { append(new LIR_Op2(lir_throw, exceptionPC, exceptionOop, LIR_OprFact::illegalOpr, info)); @@ -2034,15 +2041,17 @@ class LIR_List: public CompilationResourceObj { void fpop_raw() { append(new LIR_Op0(lir_fpop_raw)); } + void instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch, ciMethod* profiled_method, int profiled_bci); + void store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception); + void checkcast (LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_exception, CodeEmitInfo* info_for_patch, CodeStub* stub, ciMethod* profiled_method, int profiled_bci); - void instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch); - void store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception); - // methodDataOop profiling - void profile_call(ciMethod* method, int bci, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* cha_klass) { append(new LIR_OpProfileCall(lir_profile_call, method, bci, mdo, recv, t1, cha_klass)); } + void profile_call(ciMethod* method, int bci, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* cha_klass) { + append(new LIR_OpProfileCall(lir_profile_call, method, bci, mdo, recv, t1, cha_klass)); + } }; void print_LIR(BlockList* blocks); diff --git a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp index ee3c5ea8c5e..de2a1a9f21d 100644 --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp @@ -548,6 +548,16 @@ void LIR_Assembler::emit_op1(LIR_Op1* op) { monitor_address(op->in_opr()->as_constant_ptr()->as_jint(), op->result_opr()); break; +#ifdef SPARC + case lir_pack64: + pack64(op->in_opr(), op->result_opr()); + break; + + case lir_unpack64: + unpack64(op->in_opr(), op->result_opr()); + break; +#endif + case lir_unwind: unwind_op(op->in_opr()); break; diff --git a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp index e40ebd51d1e..a195cd135bf 100644 --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp @@ -187,6 +187,7 @@ class LIR_Assembler: public CompilationResourceObj { void emit_alloc_obj(LIR_OpAllocObj* op); void emit_alloc_array(LIR_OpAllocArray* op); void emit_opTypeCheck(LIR_OpTypeCheck* op); + void emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null); void emit_compare_and_swap(LIR_OpCompareAndSwap* op); void emit_lock(LIR_OpLock* op); void emit_call(LIR_OpJavaCall* op); diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 4e7605f2685..e519cfcfb1d 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -480,16 +480,6 @@ void LIRGenerator::nio_range_check(LIR_Opr buffer, LIR_Opr index, LIR_Opr result } -// increment a counter returning the incremented value -LIR_Opr LIRGenerator::increment_and_return_counter(LIR_Opr base, int offset, int increment) { - LIR_Address* counter = new LIR_Address(base, offset, T_INT); - LIR_Opr result = new_register(T_INT); - __ load(counter, result); - __ add(result, LIR_OprFact::intConst(increment), result); - __ store(result, counter); - return result; -} - void LIRGenerator::arithmetic_op(Bytecodes::Code code, LIR_Opr result, LIR_Opr left, LIR_Opr right, bool is_strictfp, LIR_Opr tmp_op, CodeEmitInfo* info) { LIR_Opr result_op = result; @@ -821,7 +811,6 @@ LIR_Opr LIRGenerator::force_to_spill(LIR_Opr value, BasicType t) { return tmp; } - void LIRGenerator::profile_branch(If* if_instr, If::Condition cond) { if (if_instr->should_profile()) { ciMethod* method = if_instr->profiled_method(); @@ -836,24 +825,32 @@ void LIRGenerator::profile_branch(If* if_instr, If::Condition cond) { assert(data->is_BranchData(), "need BranchData for two-way branches"); int taken_count_offset = md->byte_offset_of_slot(data, BranchData::taken_offset()); int not_taken_count_offset = md->byte_offset_of_slot(data, BranchData::not_taken_offset()); + if (if_instr->is_swapped()) { + int t = taken_count_offset; + taken_count_offset = not_taken_count_offset; + not_taken_count_offset = t; + } + LIR_Opr md_reg = new_register(T_OBJECT); - __ move(LIR_OprFact::oopConst(md->constant_encoding()), md_reg); - LIR_Opr data_offset_reg = new_register(T_INT); + __ oop2reg(md->constant_encoding(), md_reg); + + LIR_Opr data_offset_reg = new_pointer_register(); __ cmove(lir_cond(cond), - LIR_OprFact::intConst(taken_count_offset), - LIR_OprFact::intConst(not_taken_count_offset), + LIR_OprFact::intptrConst(taken_count_offset), + LIR_OprFact::intptrConst(not_taken_count_offset), data_offset_reg); - LIR_Opr data_reg = new_register(T_INT); - LIR_Address* data_addr = new LIR_Address(md_reg, data_offset_reg, T_INT); + + // MDO cells are intptr_t, so the data_reg width is arch-dependent. + LIR_Opr data_reg = new_pointer_register(); + LIR_Address* data_addr = new LIR_Address(md_reg, data_offset_reg, data_reg->type()); __ move(LIR_OprFact::address(data_addr), data_reg); - LIR_Address* fake_incr_value = new LIR_Address(data_reg, DataLayout::counter_increment, T_INT); // Use leal instead of add to avoid destroying condition codes on x86 + LIR_Address* fake_incr_value = new LIR_Address(data_reg, DataLayout::counter_increment, T_INT); __ leal(LIR_OprFact::address(fake_incr_value), data_reg); __ move(data_reg, LIR_OprFact::address(data_addr)); } } - // Phi technique: // This is about passing live values from one basic block to the other. // In code generated with Java it is rather rare that more than one @@ -1305,8 +1302,6 @@ void LIRGenerator::G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, bool patc LIR_Opr flag_val = new_register(T_INT); __ load(mark_active_flag_addr, flag_val); - LabelObj* start_store = new LabelObj(); - LIR_PatchCode pre_val_patch_code = patch ? lir_patch_normal : lir_patch_none; @@ -1757,7 +1752,7 @@ void LIRGenerator::do_Throw(Throw* x) { #ifndef PRODUCT if (PrintC1Statistics) { - increment_counter(Runtime1::throw_count_address()); + increment_counter(Runtime1::throw_count_address(), T_INT); } #endif @@ -2191,12 +2186,41 @@ void LIRGenerator::do_Goto(Goto* x) { ValueStack* state = x->state_before() ? x->state_before() : x->state(); // increment backedge counter if needed - increment_backedge_counter(state_for(x, state)); - + CodeEmitInfo* info = state_for(x, state); + increment_backedge_counter(info, info->bci()); CodeEmitInfo* safepoint_info = state_for(x, state); __ safepoint(safepoint_poll_register(), safepoint_info); } + // Gotos can be folded Ifs, handle this case. + if (x->should_profile()) { + ciMethod* method = x->profiled_method(); + assert(method != NULL, "method should be set if branch is profiled"); + ciMethodData* md = method->method_data(); + if (md == NULL) { + bailout("out of memory building methodDataOop"); + return; + } + ciProfileData* data = md->bci_to_data(x->profiled_bci()); + assert(data != NULL, "must have profiling data"); + int offset; + if (x->direction() == Goto::taken) { + assert(data->is_BranchData(), "need BranchData for two-way branches"); + offset = md->byte_offset_of_slot(data, BranchData::taken_offset()); + } else if (x->direction() == Goto::not_taken) { + assert(data->is_BranchData(), "need BranchData for two-way branches"); + offset = md->byte_offset_of_slot(data, BranchData::not_taken_offset()); + } else { + assert(data->is_JumpData(), "need JumpData for branches"); + offset = md->byte_offset_of_slot(data, JumpData::taken_offset()); + } + LIR_Opr md_reg = new_register(T_OBJECT); + __ oop2reg(md->constant_encoding(), md_reg); + + increment_counter(new LIR_Address(md_reg, offset, + NOT_LP64(T_INT) LP64_ONLY(T_LONG)), DataLayout::counter_increment); + } + // emit phi-instruction move after safepoint since this simplifies // describing the state as the safepoint. move_to_phi(x->state()); @@ -2279,7 +2303,10 @@ void LIRGenerator::do_Base(Base* x) { } // increment invocation counters if needed - increment_invocation_counter(new CodeEmitInfo(0, scope()->start()->state(), NULL)); + if (!method()->is_accessor()) { // Accessors do not have MDOs, so no counting. + CodeEmitInfo* info = new CodeEmitInfo(InvocationEntryBci, scope()->start()->state(), NULL); + increment_invocation_counter(info); + } // all blocks with a successor must end with an unconditional jump // to the successor even if they are consecutive @@ -2613,12 +2640,12 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { } } - void LIRGenerator::do_ProfileCall(ProfileCall* x) { // Need recv in a temporary register so it interferes with the other temporaries LIR_Opr recv = LIR_OprFact::illegalOpr; LIR_Opr mdo = new_register(T_OBJECT); - LIR_Opr tmp = new_register(T_INT); + // tmp is used to hold the counters on SPARC + LIR_Opr tmp = new_pointer_register(); if (x->recv() != NULL) { LIRItem value(x->recv(), this); value.load_item(); @@ -2628,14 +2655,69 @@ void LIRGenerator::do_ProfileCall(ProfileCall* x) { __ profile_call(x->method(), x->bci_of_invoke(), mdo, recv, tmp, x->known_holder()); } - -void LIRGenerator::do_ProfileCounter(ProfileCounter* x) { - LIRItem mdo(x->mdo(), this); - mdo.load_item(); - - increment_counter(new LIR_Address(mdo.result(), x->offset(), T_INT), x->increment()); +void LIRGenerator::do_ProfileInvoke(ProfileInvoke* x) { + // We can safely ignore accessors here, since c2 will inline them anyway, + // accessors are also always mature. + if (!x->inlinee()->is_accessor()) { + CodeEmitInfo* info = state_for(x, x->state(), true); + // Increment invocation counter, don't notify the runtime, because we don't inline loops, + increment_event_counter_impl(info, x->inlinee(), 0, InvocationEntryBci, false, false); + } } +void LIRGenerator::increment_event_counter(CodeEmitInfo* info, int bci, bool backedge) { + int freq_log; + int level = compilation()->env()->comp_level(); + if (level == CompLevel_limited_profile) { + freq_log = (backedge ? Tier2BackedgeNotifyFreqLog : Tier2InvokeNotifyFreqLog); + } else if (level == CompLevel_full_profile) { + freq_log = (backedge ? Tier3BackedgeNotifyFreqLog : Tier3InvokeNotifyFreqLog); + } else { + ShouldNotReachHere(); + } + // Increment the appropriate invocation/backedge counter and notify the runtime. + increment_event_counter_impl(info, info->scope()->method(), (1 << freq_log) - 1, bci, backedge, true); +} + +void LIRGenerator::increment_event_counter_impl(CodeEmitInfo* info, + ciMethod *method, int frequency, + int bci, bool backedge, bool notify) { + assert(frequency == 0 || is_power_of_2(frequency + 1), "Frequency must be x^2 - 1 or 0"); + int level = _compilation->env()->comp_level(); + assert(level > CompLevel_simple, "Shouldn't be here"); + + int offset = -1; + LIR_Opr counter_holder = new_register(T_OBJECT); + LIR_Opr meth; + if (level == CompLevel_limited_profile) { + offset = in_bytes(backedge ? methodOopDesc::backedge_counter_offset() : + methodOopDesc::invocation_counter_offset()); + __ oop2reg(method->constant_encoding(), counter_holder); + meth = counter_holder; + } else if (level == CompLevel_full_profile) { + offset = in_bytes(backedge ? methodDataOopDesc::backedge_counter_offset() : + methodDataOopDesc::invocation_counter_offset()); + __ oop2reg(method->method_data()->constant_encoding(), counter_holder); + meth = new_register(T_OBJECT); + __ oop2reg(method->constant_encoding(), meth); + } else { + ShouldNotReachHere(); + } + LIR_Address* counter = new LIR_Address(counter_holder, offset, T_INT); + LIR_Opr result = new_register(T_INT); + __ load(counter, result); + __ add(result, LIR_OprFact::intConst(InvocationCounter::count_increment), result); + __ store(result, counter); + if (notify) { + LIR_Opr mask = load_immediate(frequency << InvocationCounter::count_shift, T_INT); + __ logical_and(result, mask, result); + __ cmp(lir_cond_equal, result, LIR_OprFact::intConst(0)); + // The bci for info can point to cmp for if's we want the if bci + CodeStub* overflow = new CounterOverflowStub(info, bci, meth); + __ branch(lir_cond_equal, T_INT, overflow); + __ branch_destination(overflow->continuation()); + } +} LIR_Opr LIRGenerator::call_runtime(Value arg1, address entry, ValueType* result_type, CodeEmitInfo* info) { LIRItemList args(1); @@ -2748,28 +2830,3 @@ LIR_Opr LIRGenerator::call_runtime(BasicTypeArray* signature, LIRItemList* args, return result; } - - -void LIRGenerator::increment_invocation_counter(CodeEmitInfo* info, bool backedge) { -#ifdef TIERED - if (_compilation->env()->comp_level() == CompLevel_fast_compile && - (method()->code_size() >= Tier1BytecodeLimit || backedge)) { - int limit = InvocationCounter::Tier1InvocationLimit; - int offset = in_bytes(methodOopDesc::invocation_counter_offset() + - InvocationCounter::counter_offset()); - if (backedge) { - limit = InvocationCounter::Tier1BackEdgeLimit; - offset = in_bytes(methodOopDesc::backedge_counter_offset() + - InvocationCounter::counter_offset()); - } - - LIR_Opr meth = new_register(T_OBJECT); - __ oop2reg(method()->constant_encoding(), meth); - LIR_Opr result = increment_and_return_counter(meth, offset, InvocationCounter::count_increment); - __ cmp(lir_cond_aboveEqual, result, LIR_OprFact::intConst(limit)); - CodeStub* overflow = new CounterOverflowStub(info, info->bci()); - __ branch(lir_cond_aboveEqual, T_INT, overflow); - __ branch_destination(overflow->continuation()); - } -#endif -} diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp index 4a69bd842ed..f1c53941aaf 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -196,6 +196,9 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { LIR_Opr load_constant(Constant* x); LIR_Opr load_constant(LIR_Const* constant); + // Given an immediate value, return an operand usable in logical ops. + LIR_Opr load_immediate(int x, BasicType type); + void set_result(Value x, LIR_Opr opr) { assert(opr->is_valid(), "must set to valid value"); assert(x->operand()->is_illegal(), "operand should never change"); @@ -213,8 +216,6 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { LIR_Opr round_item(LIR_Opr opr); LIR_Opr force_to_spill(LIR_Opr value, BasicType t); - void profile_branch(If* if_instr, If::Condition cond); - PhiResolverState& resolver_state() { return _resolver_state; } void move_to_phi(PhiResolver* resolver, Value cur_val, Value sux_val); @@ -285,12 +286,9 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void arithmetic_call_op (Bytecodes::Code code, LIR_Opr result, LIR_OprList* args); - void increment_counter(address counter, int step = 1); + void increment_counter(address counter, BasicType type, int step = 1); void increment_counter(LIR_Address* addr, int step = 1); - // increment a counter returning the incremented value - LIR_Opr increment_and_return_counter(LIR_Opr base, int offset, int increment); - // is_strictfp is only needed for mul and div (and only generates different code on i486) void arithmetic_op(Bytecodes::Code code, LIR_Opr result, LIR_Opr left, LIR_Opr right, bool is_strictfp, LIR_Opr tmp, CodeEmitInfo* info = NULL); // machine dependent. returns true if it emitted code for the multiply @@ -347,9 +345,21 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { bool can_store_as_constant(Value i, BasicType type) const; LIR_Opr safepoint_poll_register(); - void increment_invocation_counter(CodeEmitInfo* info, bool backedge = false); - void increment_backedge_counter(CodeEmitInfo* info) { - increment_invocation_counter(info, true); + + void profile_branch(If* if_instr, If::Condition cond); + void increment_event_counter_impl(CodeEmitInfo* info, + ciMethod *method, int frequency, + int bci, bool backedge, bool notify); + void increment_event_counter(CodeEmitInfo* info, int bci, bool backedge); + void increment_invocation_counter(CodeEmitInfo *info) { + if (compilation()->count_invocations()) { + increment_event_counter(info, InvocationEntryBci, false); + } + } + void increment_backedge_counter(CodeEmitInfo* info, int bci) { + if (compilation()->count_backedges()) { + increment_event_counter(info, bci, true); + } } CodeEmitInfo* state_for(Instruction* x, ValueStack* state, bool ignore_xhandler = false); @@ -503,7 +513,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x); virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); virtual void do_ProfileCall (ProfileCall* x); - virtual void do_ProfileCounter (ProfileCounter* x); + virtual void do_ProfileInvoke (ProfileInvoke* x); }; diff --git a/hotspot/src/share/vm/c1/c1_Optimizer.cpp b/hotspot/src/share/vm/c1/c1_Optimizer.cpp index fd5ddd53eab..d3d51cedb09 100644 --- a/hotspot/src/share/vm/c1/c1_Optimizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Optimizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -430,7 +430,7 @@ public: void do_UnsafePrefetchRead (UnsafePrefetchRead* x); void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); void do_ProfileCall (ProfileCall* x); - void do_ProfileCounter (ProfileCounter* x); + void do_ProfileInvoke (ProfileInvoke* x); }; @@ -598,7 +598,7 @@ void NullCheckVisitor::do_UnsafePutObject(UnsafePutObject* x) {} void NullCheckVisitor::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {} void NullCheckVisitor::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {} void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check(); } -void NullCheckVisitor::do_ProfileCounter (ProfileCounter* x) {} +void NullCheckVisitor::do_ProfileInvoke (ProfileInvoke* x) {} void NullCheckEliminator::visit(Value* p) { diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 96d4e713568..df05521d050 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -118,8 +118,7 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) { assert(0 <= id && id < number_of_ids, "illegal stub id"); ResourceMark rm; // create code buffer for code storage - CodeBuffer code(buffer_blob->instructions_begin(), - buffer_blob->instructions_size()); + CodeBuffer code(buffer_blob); Compilation::setup_code_buffer(&code, 0); @@ -141,9 +140,7 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) { case slow_subtype_check_id: case fpu2long_stub_id: case unwind_exception_id: -#ifndef TIERED - case counter_overflow_id: // Not generated outside the tiered world -#endif + case counter_overflow_id: #if defined(SPARC) || defined(PPC) case handle_exception_nofpu_id: // Unused on sparc #endif @@ -323,31 +320,60 @@ JRT_ENTRY(void, Runtime1::post_jvmti_exception_throw(JavaThread* thread)) } JRT_END -#ifdef TIERED -JRT_ENTRY(void, Runtime1::counter_overflow(JavaThread* thread, int bci)) - RegisterMap map(thread, false); - frame fr = thread->last_frame().sender(&map); +// This is a helper to allow us to safepoint but allow the outer entry +// to be safepoint free if we need to do an osr +static nmethod* counter_overflow_helper(JavaThread* THREAD, int branch_bci, methodOopDesc* m) { + nmethod* osr_nm = NULL; + methodHandle method(THREAD, m); + + RegisterMap map(THREAD, false); + frame fr = THREAD->last_frame().sender(&map); nmethod* nm = (nmethod*) fr.cb(); - assert(nm!= NULL && nm->is_nmethod(), "what?"); - methodHandle method(thread, nm->method()); - if (bci == 0) { - // invocation counter overflow - if (!Tier1CountOnly) { - CompilationPolicy::policy()->method_invocation_event(method, CHECK); - } else { - method()->invocation_counter()->reset(); - } - } else { - if (!Tier1CountOnly) { - // Twe have a bci but not the destination bci and besides a backedge - // event is more for OSR which we don't want here. - CompilationPolicy::policy()->method_invocation_event(method, CHECK); - } else { - method()->backedge_counter()->reset(); + assert(nm!= NULL && nm->is_nmethod(), "Sanity check"); + methodHandle enclosing_method(THREAD, nm->method()); + + CompLevel level = (CompLevel)nm->comp_level(); + int bci = InvocationEntryBci; + if (branch_bci != InvocationEntryBci) { + // Compute desination bci + address pc = method()->code_base() + branch_bci; + Bytecodes::Code branch = Bytecodes::code_at(pc, method()); + int offset = 0; + switch (branch) { + case Bytecodes::_if_icmplt: case Bytecodes::_iflt: + case Bytecodes::_if_icmpgt: case Bytecodes::_ifgt: + case Bytecodes::_if_icmple: case Bytecodes::_ifle: + case Bytecodes::_if_icmpge: case Bytecodes::_ifge: + case Bytecodes::_if_icmpeq: case Bytecodes::_if_acmpeq: case Bytecodes::_ifeq: + case Bytecodes::_if_icmpne: case Bytecodes::_if_acmpne: case Bytecodes::_ifne: + case Bytecodes::_ifnull: case Bytecodes::_ifnonnull: case Bytecodes::_goto: + offset = (int16_t)Bytes::get_Java_u2(pc + 1); + break; + case Bytecodes::_goto_w: + offset = Bytes::get_Java_u4(pc + 1); + break; + default: ; } + bci = branch_bci + offset; } + + osr_nm = CompilationPolicy::policy()->event(enclosing_method, method, branch_bci, bci, level, THREAD); + return osr_nm; +} + +JRT_BLOCK_ENTRY(address, Runtime1::counter_overflow(JavaThread* thread, int bci, methodOopDesc* method)) + nmethod* osr_nm; + JRT_BLOCK + osr_nm = counter_overflow_helper(thread, bci, method); + if (osr_nm != NULL) { + RegisterMap map(thread, false); + frame fr = thread->last_frame().sender(&map); + VM_DeoptimizeFrame deopt(thread, fr.id()); + VMThread::execute(&deopt); + } + JRT_BLOCK_END + return NULL; JRT_END -#endif // TIERED extern void vm_exit(int code); @@ -899,7 +925,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i NativeMovConstReg* n_copy = nativeMovConstReg_at(copy_buff); assert(n_copy->data() == 0 || - n_copy->data() == (int)Universe::non_oop_word(), + n_copy->data() == (intptr_t)Universe::non_oop_word(), "illegal init value"); assert(load_klass() != NULL, "klass not set"); n_copy->set_data((intx) (load_klass())); diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.hpp b/hotspot/src/share/vm/c1/c1_Runtime1.hpp index 1f31ebfbf16..38571439c9b 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.hpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,9 +123,7 @@ class Runtime1: public AllStatic { static void new_object_array(JavaThread* thread, klassOopDesc* klass, jint length); static void new_multi_array (JavaThread* thread, klassOopDesc* klass, int rank, jint* dims); -#ifdef TIERED - static void counter_overflow(JavaThread* thread, int bci); -#endif // TIERED + static address counter_overflow(JavaThread* thread, int bci, methodOopDesc* method); static void unimplemented_entry (JavaThread* thread, StubID id); @@ -155,7 +153,7 @@ class Runtime1: public AllStatic { // stubs static CodeBlob* blob_for (StubID id); - static address entry_for(StubID id) { return blob_for(id)->instructions_begin(); } + static address entry_for(StubID id) { return blob_for(id)->code_begin(); } static const char* name_for (StubID id); static const char* name_for_address(address entry); diff --git a/hotspot/src/share/vm/c1/c1_ValueMap.hpp b/hotspot/src/share/vm/c1/c1_ValueMap.hpp index 9c54e19a976..0bf25f031bb 100644 --- a/hotspot/src/share/vm/c1/c1_ValueMap.hpp +++ b/hotspot/src/share/vm/c1/c1_ValueMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -185,11 +185,11 @@ class ValueNumberingVisitor: public InstructionVisitor { void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ } void do_RoundFP (RoundFP* x) { /* nothing to do */ } void do_UnsafeGetRaw (UnsafeGetRaw* x) { /* nothing to do */ } + void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; void do_UnsafeGetObject(UnsafeGetObject* x) { /* nothing to do */ } void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ } void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ } void do_ProfileCall (ProfileCall* x) { /* nothing to do */ } - void do_ProfileCounter (ProfileCounter* x) { /* nothing to do */ } }; diff --git a/hotspot/src/share/vm/c1/c1_globals.hpp b/hotspot/src/share/vm/c1/c1_globals.hpp index 6a71888360f..25633a63832 100644 --- a/hotspot/src/share/vm/c1/c1_globals.hpp +++ b/hotspot/src/share/vm/c1/c1_globals.hpp @@ -25,12 +25,6 @@ // // Defines all global flags used by the client compiler. // -#ifndef TIERED - #define NOT_TIERED(x) x -#else - #define NOT_TIERED(x) -#endif - #define C1_FLAGS(develop, develop_pd, product, product_pd, notproduct) \ \ /* Printing */ \ @@ -55,7 +49,7 @@ notproduct(bool, PrintIRDuringConstruction, false, \ "Print IR as it's being constructed (helpful for debugging frontend)")\ \ - notproduct(bool, PrintPhiFunctions, false, \ + notproduct(bool, PrintPhiFunctions, false, \ "Print phi functions when they are created and simplified") \ \ notproduct(bool, PrintIR, false, \ @@ -279,41 +273,29 @@ product_pd(intx, SafepointPollOffset, \ "Offset added to polling address (Intel only)") \ \ - product(bool, UseNewFeature1, false, \ - "Enable new feature for testing. This is a dummy flag.") \ - \ - product(bool, UseNewFeature2, false, \ - "Enable new feature for testing. This is a dummy flag.") \ - \ - product(bool, UseNewFeature3, false, \ - "Enable new feature for testing. This is a dummy flag.") \ - \ - product(bool, UseNewFeature4, false, \ - "Enable new feature for testing. This is a dummy flag.") \ - \ develop(bool, ComputeExactFPURegisterUsage, true, \ "Compute additional live set for fpu registers to simplify fpu stack merge (Intel only)") \ \ - product(bool, Tier1ProfileCalls, true, \ + product(bool, C1ProfileCalls, true, \ "Profile calls when generating code for updating MDOs") \ \ - product(bool, Tier1ProfileVirtualCalls, true, \ + product(bool, C1ProfileVirtualCalls, true, \ "Profile virtual calls when generating code for updating MDOs") \ \ - product(bool, Tier1ProfileInlinedCalls, true, \ + product(bool, C1ProfileInlinedCalls, true, \ "Profile inlined calls when generating code for updating MDOs") \ \ - product(bool, Tier1ProfileBranches, true, \ + product(bool, C1ProfileBranches, true, \ "Profile branches when generating code for updating MDOs") \ \ - product(bool, Tier1ProfileCheckcasts, true, \ + product(bool, C1ProfileCheckcasts, true, \ "Profile checkcasts when generating code for updating MDOs") \ \ - product(bool, Tier1OptimizeVirtualCallProfiling, true, \ - "Use CHA and exact type results at call sites when updating MDOs") \ + product(bool, C1OptimizeVirtualCallProfiling, true, \ + "Use CHA and exact type results at call sites when updating MDOs")\ \ - develop(bool, Tier1CountOnly, false, \ - "Don't schedule tier 2 compiles. Enter VM only") \ + product(bool, C1UpdateMethodData, trueInTiered, \ + "Update methodDataOops in Tier1-generated code") \ \ develop(bool, PrintCFGToFile, false, \ "print control flow graph to a separate file during compilation") \ diff --git a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp index 6642271cbb7..143101dae68 100644 --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp @@ -92,11 +92,11 @@ public: empty_map.clear(); } - ArgumentMap raw_pop() { assert(_stack_height > 0, "stack underflow"); return _stack[--_stack_height]; } + ArgumentMap raw_pop() { guarantee(_stack_height > 0, "stack underflow"); return _stack[--_stack_height]; } ArgumentMap apop() { return raw_pop(); } void spop() { raw_pop(); } void lpop() { spop(); spop(); } - void raw_push(ArgumentMap i) { assert(_stack_height < _max_stack, "stack overflow"); _stack[_stack_height++] = i; } + void raw_push(ArgumentMap i) { guarantee(_stack_height < _max_stack, "stack overflow"); _stack[_stack_height++] = i; } void apush(ArgumentMap i) { raw_push(i); } void spush() { raw_push(empty_map); } void lpush() { spush(); spush(); } @@ -365,12 +365,19 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl case Bytecodes::_ldc: case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: - if (type2size[s.get_constant().basic_type()] == 1) { - state.spush(); - } else { + { + // Avoid calling get_constant() which will try to allocate + // unloaded constant. We need only constant's type. + int index = s.get_constant_pool_index(); + constantTag tag = s.get_constant_pool_tag(index); + if (tag.is_long() || tag.is_double()) { + // Only longs and doubles use 2 stack slots. state.lpush(); + } else { + state.spush(); } break; + } case Bytecodes::_aload: state.apush(state._vars[s.get_index()]); break; diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index de1fb564d76..51682101382 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -956,18 +956,18 @@ void ciEnv::register_method(ciMethod* target, if (task() != NULL) task()->set_code(nm); if (entry_bci == InvocationEntryBci) { -#ifdef TIERED - // If there is an old version we're done with it - nmethod* old = method->code(); - if (TraceMethodReplacement && old != NULL) { - ResourceMark rm; - char *method_name = method->name_and_sig_as_C_string(); - tty->print_cr("Replacing method %s", method_name); + if (TieredCompilation) { + // If there is an old version we're done with it + nmethod* old = method->code(); + if (TraceMethodReplacement && old != NULL) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + tty->print_cr("Replacing method %s", method_name); + } + if (old != NULL ) { + old->make_not_entrant(); + } } - if (old != NULL ) { - old->make_not_entrant(); - } -#endif // TIERED if (TraceNMethodInstalls ) { ResourceMark rm; char *method_name = method->name_and_sig_as_C_string(); @@ -1011,7 +1011,7 @@ ciKlass* ciEnv::find_system_klass(ciSymbol* klass_name) { // ------------------------------------------------------------------ // ciEnv::comp_level int ciEnv::comp_level() { - if (task() == NULL) return CompLevel_full_optimization; + if (task() == NULL) return CompLevel_highest_tier; return task()->comp_level(); } diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 463c3b89dae..5b09d03a1e5 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -49,7 +49,8 @@ ciMethod::ciMethod(methodHandle h_m) : ciObject(h_m) { _handler_count = h_m()->exception_table()->length() / 4; _uses_monitors = h_m()->access_flags().has_monitor_bytecodes(); _balanced_monitors = !_uses_monitors || h_m()->access_flags().is_monitor_matching(); - _is_compilable = !h_m()->is_not_compilable(); + _is_c1_compilable = !h_m()->is_not_c1_compilable(); + _is_c2_compilable = !h_m()->is_not_c2_compilable(); // Lazy fields, filled in on demand. Require allocation. _code = NULL; _exception_handlers = NULL; @@ -61,11 +62,12 @@ ciMethod::ciMethod(methodHandle h_m) : ciObject(h_m) { #endif // COMPILER2 || SHARK ciEnv *env = CURRENT_ENV; - if (env->jvmti_can_hotswap_or_post_breakpoint() && _is_compilable) { + if (env->jvmti_can_hotswap_or_post_breakpoint() && can_be_compiled()) { // 6328518 check hotswap conditions under the right lock. MutexLocker locker(Compile_lock); if (Dependencies::check_evol_method(h_m()) != NULL) { - _is_compilable = false; + _is_c1_compilable = false; + _is_c2_compilable = false; } } else { CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); @@ -93,7 +95,7 @@ ciMethod::ciMethod(methodHandle h_m) : ciObject(h_m) { _signature = new (env->arena()) ciSignature(_holder, sig_symbol); _method_data = NULL; // Take a snapshot of these values, so they will be commensurate with the MDO. - if (ProfileInterpreter) { + if (ProfileInterpreter || TieredCompilation) { int invcnt = h_m()->interpreter_invocation_count(); // if the value overflowed report it as max int _interpreter_invocation_count = invcnt < 0 ? max_jint : invcnt ; @@ -437,11 +439,26 @@ ciCallProfile ciMethod::call_profile_at_bci(int bci) { // In addition, virtual call sites have receiver type information int receivers_count_total = 0; int morphism = 0; + // Precompute morphism for the possible fixup for (uint i = 0; i < call->row_limit(); i++) { ciKlass* receiver = call->receiver(i); if (receiver == NULL) continue; - morphism += 1; - int rcount = call->receiver_count(i); + morphism++; + } + int epsilon = 0; + if (TieredCompilation && ProfileInterpreter) { + // Interpreter and C1 treat final and special invokes differently. + // C1 will record a type, whereas the interpreter will just + // increment the count. Detect this case. + if (morphism == 1 && count > 0) { + epsilon = count; + count = 0; + } + } + for (uint i = 0; i < call->row_limit(); i++) { + ciKlass* receiver = call->receiver(i); + if (receiver == NULL) continue; + int rcount = call->receiver_count(i) + epsilon; if (rcount == 0) rcount = 1; // Should be valid value receivers_count_total += rcount; // Add the receiver to result data. @@ -687,10 +704,17 @@ int ciMethod::interpreter_call_site_count(int bci) { // invocation counts in methods. int ciMethod::scale_count(int count, float prof_factor) { if (count > 0 && method_data() != NULL) { - int current_mileage = method_data()->current_mileage(); - int creation_mileage = method_data()->creation_mileage(); - int counter_life = current_mileage - creation_mileage; + int counter_life; int method_life = interpreter_invocation_count(); + if (TieredCompilation) { + // In tiered the MDO's life is measured directly, so just use the snapshotted counters + counter_life = MAX2(method_data()->invocation_count(), method_data()->backedge_count()); + } else { + int current_mileage = method_data()->current_mileage(); + int creation_mileage = method_data()->creation_mileage(); + counter_life = current_mileage - creation_mileage; + } + // counter_life due to backedge_counter could be > method_life if (counter_life > method_life) counter_life = method_life; @@ -778,7 +802,8 @@ ciMethodData* ciMethod::method_data() { Thread* my_thread = JavaThread::current(); methodHandle h_m(my_thread, get_methodOop()); - if (Tier1UpdateMethodData && is_tier1_compile(env->comp_level())) { + // Create an MDO for the inlinee + if (TieredCompilation && is_c1_compile(env->comp_level())) { build_method_data(h_m); } @@ -885,7 +910,11 @@ bool ciMethod::has_option(const char* option) { // Have previous compilations of this method succeeded? bool ciMethod::can_be_compiled() { check_is_loaded(); - return _is_compilable; + ciEnv* env = CURRENT_ENV; + if (is_c1_compile(env->comp_level())) { + return _is_c1_compilable; + } + return _is_c2_compilable; } // ------------------------------------------------------------------ @@ -895,8 +924,13 @@ bool ciMethod::can_be_compiled() { void ciMethod::set_not_compilable() { check_is_loaded(); VM_ENTRY_MARK; - _is_compilable = false; - get_methodOop()->set_not_compilable(); + ciEnv* env = CURRENT_ENV; + if (is_c1_compile(env->comp_level())) { + _is_c1_compilable = false; + } else { + _is_c2_compilable = false; + } + get_methodOop()->set_not_compilable(env->comp_level()); } // ------------------------------------------------------------------ @@ -910,7 +944,8 @@ void ciMethod::set_not_compilable() { bool ciMethod::can_be_osr_compiled(int entry_bci) { check_is_loaded(); VM_ENTRY_MARK; - return !get_methodOop()->access_flags().is_not_osr_compilable(); + ciEnv* env = CURRENT_ENV; + return !get_methodOop()->is_not_osr_compilable(env->comp_level()); } // ------------------------------------------------------------------ @@ -920,26 +955,29 @@ bool ciMethod::has_compiled_code() { return get_methodOop()->code() != NULL; } +int ciMethod::comp_level() { + check_is_loaded(); + VM_ENTRY_MARK; + nmethod* nm = get_methodOop()->code(); + if (nm != NULL) return nm->comp_level(); + return 0; +} + // ------------------------------------------------------------------ // ciMethod::instructions_size -// This is a rough metric for "fat" methods, compared -// before inlining with InlineSmallCode. -// The CodeBlob::instructions_size accessor includes -// junk like exception handler, stubs, and constant table, -// which are not highly relevant to an inlined method. -// So we use the more specific accessor nmethod::code_size. -int ciMethod::instructions_size() { +// +// This is a rough metric for "fat" methods, compared before inlining +// with InlineSmallCode. The CodeBlob::code_size accessor includes +// junk like exception handler, stubs, and constant table, which are +// not highly relevant to an inlined method. So we use the more +// specific accessor nmethod::insts_size. +int ciMethod::instructions_size(int comp_level) { GUARDED_VM_ENTRY( nmethod* code = get_methodOop()->code(); - // if there's no compiled code or the code was produced by the - // tier1 profiler return 0 for the code size. This should - // probably be based on the compilation level of the nmethod but - // that currently isn't properly recorded. - if (code == NULL || - (TieredCompilation && code->compiler() != NULL && code->compiler()->is_c1())) { - return 0; + if (code != NULL && (comp_level == CompLevel_any || comp_level == code->comp_level())) { + return code->code_end() - code->verified_entry_point(); } - return code->code_end() - code->verified_entry_point(); + return 0; ) } diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 3a7a4a3e7f9..abf53ca0742 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -61,7 +61,8 @@ class ciMethod : public ciObject { bool _uses_monitors; bool _balanced_monitors; - bool _is_compilable; + bool _is_c1_compilable; + bool _is_c2_compilable; bool _can_be_statically_bound; // Lazy fields, filled in on demand @@ -127,6 +128,8 @@ class ciMethod : public ciObject { int interpreter_invocation_count() const { check_is_loaded(); return _interpreter_invocation_count; } int interpreter_throwout_count() const { check_is_loaded(); return _interpreter_throwout_count; } + int comp_level(); + Bytecodes::Code java_code_at_bci(int bci) { address bcp = code() + bci; return Bytecodes::java_code_at(bcp); @@ -209,7 +212,7 @@ class ciMethod : public ciObject { bool can_be_osr_compiled(int entry_bci); void set_not_compilable(); bool has_compiled_code(); - int instructions_size(); + int instructions_size(int comp_level = CompLevel_any); void log_nmethod_identity(xmlStream* log); bool is_not_reached(int bci); bool was_executed_more_than(int times); diff --git a/hotspot/src/share/vm/ci/ciMethodData.cpp b/hotspot/src/share/vm/ci/ciMethodData.cpp index 05287892e24..7bc50901d81 100644 --- a/hotspot/src/share/vm/ci/ciMethodData.cpp +++ b/hotspot/src/share/vm/ci/ciMethodData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,8 @@ ciMethodData::ciMethodData(methodDataHandle h_md) : ciObject(h_md) { _data_size = 0; _extra_data_size = 0; _current_mileage = 0; + _invocation_counter = 0; + _backedge_counter = 0; _state = empty_state; _saw_free_extra_data = false; // Set an initial hint. Don't use set_hint_di() because @@ -56,6 +58,8 @@ ciMethodData::ciMethodData() : ciObject() { _data_size = 0; _extra_data_size = 0; _current_mileage = 0; + _invocation_counter = 0; + _backedge_counter = 0; _state = empty_state; _saw_free_extra_data = false; // Set an initial hint. Don't use set_hint_di() because @@ -99,6 +103,8 @@ void ciMethodData::load_data() { } // Note: Extra data are all BitData, and do not need translation. _current_mileage = methodDataOopDesc::mileage_of(mdo->method()); + _invocation_counter = mdo->invocation_count(); + _backedge_counter = mdo->backedge_count(); _state = mdo->is_mature()? mature_state: immature_state; _eflags = mdo->eflags(); @@ -253,6 +259,23 @@ void ciMethodData::update_escape_info() { } } +void ciMethodData::set_compilation_stats(short loops, short blocks) { + VM_ENTRY_MARK; + methodDataOop mdo = get_methodDataOop(); + if (mdo != NULL) { + mdo->set_num_loops(loops); + mdo->set_num_blocks(blocks); + } +} + +void ciMethodData::set_would_profile(bool p) { + VM_ENTRY_MARK; + methodDataOop mdo = get_methodDataOop(); + if (mdo != NULL) { + mdo->set_would_profile(p); + } +} + bool ciMethodData::has_escape_info() { return eflag_set(methodDataOopDesc::estimated); } diff --git a/hotspot/src/share/vm/ci/ciMethodData.hpp b/hotspot/src/share/vm/ci/ciMethodData.hpp index 52cbb604bb8..3930e88393e 100644 --- a/hotspot/src/share/vm/ci/ciMethodData.hpp +++ b/hotspot/src/share/vm/ci/ciMethodData.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -162,6 +162,12 @@ private: // Maturity of the oop when the snapshot is taken. int _current_mileage; + // These counters hold the age of MDO in tiered. In tiered we can have the same method + // running at different compilation levels concurrently. So, in order to precisely measure + // its maturity we need separate counters. + int _invocation_counter; + int _backedge_counter; + // Coherent snapshot of original header. methodDataOopDesc _orig; @@ -223,6 +229,16 @@ public: int creation_mileage() { return _orig.creation_mileage(); } int current_mileage() { return _current_mileage; } + int invocation_count() { return _invocation_counter; } + int backedge_count() { return _backedge_counter; } + // Transfer information about the method to methodDataOop. + // would_profile means we would like to profile this method, + // meaning it's not trivial. + void set_would_profile(bool p); + // Also set the numer of loops and blocks in the method. + // Again, this is used to determine if a method is trivial. + void set_compilation_stats(short loops, short blocks); + void load_data(); // Convert a dp (data pointer) to a di (data index). diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index cd2432f2157..1495e87726f 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -1292,7 +1292,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) { // Iterate over all methods in class for (int n = 0; n < k->methods()->length(); n++) { methodHandle m (THREAD, methodOop(k->methods()->obj_at(n))); - if (CompilationPolicy::canBeCompiled(m)) { + if (CompilationPolicy::can_be_compiled(m)) { if (++_codecache_sweep_counter == CompileTheWorldSafepointInterval) { // Give sweeper a chance to keep up with CTW @@ -1301,7 +1301,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) { _codecache_sweep_counter = 0; } // Force compilation - CompileBroker::compile_method(m, InvocationEntryBci, + CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_initial_compile, methodHandle(), 0, "CTW", THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; @@ -1315,7 +1315,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) { nm->make_not_entrant(); m->clear_code(); } - CompileBroker::compile_method(m, InvocationEntryBci, + CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_full_optimization, methodHandle(), 0, "CTW", THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index 4fa73e90fc0..fd9e42d7169 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -2424,12 +2424,15 @@ int java_dyn_MethodType::ptype_count(oop mt) { int java_dyn_MethodTypeForm::_vmslots_offset; int java_dyn_MethodTypeForm::_erasedType_offset; +int java_dyn_MethodTypeForm::_genericInvoker_offset; void java_dyn_MethodTypeForm::compute_offsets() { klassOop k = SystemDictionary::MethodTypeForm_klass(); if (k != NULL) { compute_optional_offset(_vmslots_offset, k, vmSymbols::vmslots_name(), vmSymbols::int_signature(), true); compute_optional_offset(_erasedType_offset, k, vmSymbols::erasedType_name(), vmSymbols::java_dyn_MethodType_signature(), true); + compute_optional_offset(_genericInvoker_offset, k, vmSymbols::genericInvoker_name(), vmSymbols::java_dyn_MethodHandle_signature(), true); + if (_genericInvoker_offset == 0) _genericInvoker_offset = -1; // set to explicit "empty" value } } @@ -2443,6 +2446,11 @@ oop java_dyn_MethodTypeForm::erasedType(oop mtform) { return mtform->obj_field(_erasedType_offset); } +oop java_dyn_MethodTypeForm::genericInvoker(oop mtform) { + assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only"); + return mtform->obj_field(_genericInvoker_offset); +} + // Support for java_dyn_CallSite diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 5a3792033e7..7cd03c1d468 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -1048,6 +1048,7 @@ class java_dyn_MethodTypeForm: AllStatic { private: static int _vmslots_offset; // number of argument slots needed static int _erasedType_offset; // erasedType = canonical MethodType + static int _genericInvoker_offset; // genericInvoker = adapter for invokeGeneric static void compute_offsets(); @@ -1055,10 +1056,12 @@ class java_dyn_MethodTypeForm: AllStatic { // Accessors static int vmslots(oop mtform); static oop erasedType(oop mtform); + static oop genericInvoker(oop mtform); // Accessors for code generation: static int vmslots_offset_in_bytes() { return _vmslots_offset; } static int erasedType_offset_in_bytes() { return _erasedType_offset; } + static int genericInvoker_offset_in_bytes() { return _genericInvoker_offset; } }; diff --git a/hotspot/src/share/vm/classfile/stackMapTable.cpp b/hotspot/src/share/vm/classfile/stackMapTable.cpp index f3acdd14a61..e34fc5948aa 100644 --- a/hotspot/src/share/vm/classfile/stackMapTable.cpp +++ b/hotspot/src/share/vm/classfile/stackMapTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,6 +152,7 @@ void StackMapTable::print() const { int32_t StackMapReader::chop( VerificationType* locals, int32_t length, int32_t chops) { + if (locals == NULL) return -1; int32_t pos = length - 1; for (int32_t i=0; iis_Compiler_thread()) return NULL; // do not attempt from within compiler + bool for_invokeGeneric = (name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name)); bool found_on_bcp = false; - Handle mt = find_method_handle_type(signature(), accessing_klass, found_on_bcp, CHECK_NULL); + Handle mt = find_method_handle_type(signature(), accessing_klass, + for_invokeGeneric, + found_on_bcp, CHECK_NULL); KlassHandle mh_klass = SystemDictionaryHandles::MethodHandle_klass(); methodHandle m = methodOopDesc::make_invoke_method(mh_klass, name, signature, mt, CHECK_NULL); @@ -2393,6 +2396,7 @@ methodOop SystemDictionary::find_method_handle_invoke(symbolHandle name, // consistent with this loader. Handle SystemDictionary::find_method_handle_type(symbolHandle signature, KlassHandle accessing_klass, + bool for_invokeGeneric, bool& return_bcp_flag, TRAPS) { Handle class_loader, protection_domain; @@ -2448,10 +2452,26 @@ Handle SystemDictionary::find_method_handle_type(symbolHandle signature, vmSymbols::findMethodHandleType_name(), vmSymbols::findMethodHandleType_signature(), &args, CHECK_(empty)); + Handle method_type(THREAD, (oop) result.get_jobject()); + + if (for_invokeGeneric) { + // call sun.dyn.MethodHandleNatives::notifyGenericMethodType(MethodType) -> void + JavaCallArguments args(Handle(THREAD, method_type())); + JavaValue no_result(T_VOID); + JavaCalls::call_static(&no_result, + SystemDictionary::MethodHandleNatives_klass(), + vmSymbols::notifyGenericMethodType_name(), + vmSymbols::notifyGenericMethodType_signature(), + &args, THREAD); + if (HAS_PENDING_EXCEPTION) { + // If the notification fails, just kill it. + CLEAR_PENDING_EXCEPTION; + } + } // report back to the caller with the MethodType and the "on_bcp" flag return_bcp_flag = is_on_bcp; - return Handle(THREAD, (oop) result.get_jobject()); + return method_type; } // Ask Java code to find or construct a method handle constant. @@ -2466,7 +2486,7 @@ Handle SystemDictionary::link_method_handle_constant(KlassHandle caller, Handle type; if (signature->utf8_length() > 0 && signature->byte_at(0) == '(') { bool ignore_is_on_bcp = false; - type = find_method_handle_type(signature, caller, ignore_is_on_bcp, CHECK_(empty)); + type = find_method_handle_type(signature, caller, false, ignore_is_on_bcp, CHECK_(empty)); } else { SignatureStream ss(signature(), false); if (!ss.is_done()) { diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index 11bf2257992..8d51a8a7561 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -471,6 +471,7 @@ public: // ask Java to compute a java.dyn.MethodType object for a given signature static Handle find_method_handle_type(symbolHandle signature, KlassHandle accessing_klass, + bool for_invokeGeneric, bool& return_bcp_flag, TRAPS); // ask Java to compute a java.dyn.MethodHandle object for a given CP entry diff --git a/hotspot/src/share/vm/classfile/verificationType.cpp b/hotspot/src/share/vm/classfile/verificationType.cpp index 7b507efa901..4a60b789451 100644 --- a/hotspot/src/share/vm/classfile/verificationType.cpp +++ b/hotspot/src/share/vm/classfile/verificationType.cpp @@ -54,10 +54,12 @@ bool VerificationType::is_reference_assignable_from( // any object or array is assignable to java.lang.Object return true; } - klassOop this_class = SystemDictionary::resolve_or_fail( + klassOop obj = SystemDictionary::resolve_or_fail( name_handle(), Handle(THREAD, context->class_loader()), Handle(THREAD, context->protection_domain()), true, CHECK_false); - if (this_class->klass_part()->is_interface()) { + KlassHandle this_class(THREAD, obj); + + if (this_class->is_interface()) { // We treat interfaces as java.lang.Object, including // java.lang.Cloneable and java.io.Serializable return true; @@ -65,7 +67,7 @@ bool VerificationType::is_reference_assignable_from( klassOop from_class = SystemDictionary::resolve_or_fail( from.name_handle(), Handle(THREAD, context->class_loader()), Handle(THREAD, context->protection_domain()), true, CHECK_false); - return instanceKlass::cast(from_class)->is_subclass_of(this_class); + return instanceKlass::cast(from_class)->is_subclass_of(this_class()); } } else if (is_array() && from.is_array()) { VerificationType comp_this = get_component(CHECK_false); diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 49c78eb1310..cc88ad71fd1 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -246,6 +246,8 @@ /* internal up-calls made only by the JVM, via class sun.dyn.MethodHandleNatives: */ \ template(findMethodHandleType_name, "findMethodHandleType") \ template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/dyn/MethodType;") \ + template(notifyGenericMethodType_name, "notifyGenericMethodType") \ + template(notifyGenericMethodType_signature, "(Ljava/dyn/MethodType;)V") \ template(linkMethodHandleConstant_name, "linkMethodHandleConstant") \ template(linkMethodHandleConstant_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/dyn/MethodHandle;") \ template(makeDynamicCallSite_name, "makeDynamicCallSite") \ @@ -345,6 +347,7 @@ template(ptypes_name, "ptypes") \ template(form_name, "form") \ template(erasedType_name, "erasedType") \ + template(genericInvoker_name, "genericInvoker") \ template(append_name, "append") \ \ /* non-intrinsic name/signature pairs: */ \ diff --git a/hotspot/src/share/vm/code/codeBlob.cpp b/hotspot/src/share/vm/code/codeBlob.cpp index d5e4525fc83..823eedd498d 100644 --- a/hotspot/src/share/vm/code/codeBlob.cpp +++ b/hotspot/src/share/vm/code/codeBlob.cpp @@ -39,7 +39,7 @@ unsigned int CodeBlob::allocation_size(CodeBuffer* cb, int header_size) { size += round_to(cb->total_relocation_size(), oopSize); // align the size to CodeEntryAlignment size = align_code_offset(size); - size += round_to(cb->total_code_size(), oopSize); + size += round_to(cb->total_content_size(), oopSize); size += round_to(cb->total_oop_size(), oopSize); return size; } @@ -47,8 +47,8 @@ unsigned int CodeBlob::allocation_size(CodeBuffer* cb, int header_size) { // Creates a simple CodeBlob. Sets up the size of the different regions. CodeBlob::CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size) { - assert(size == round_to(size, oopSize), "unaligned size"); - assert(locs_size == round_to(locs_size, oopSize), "unaligned size"); + assert(size == round_to(size, oopSize), "unaligned size"); + assert(locs_size == round_to(locs_size, oopSize), "unaligned size"); assert(header_size == round_to(header_size, oopSize), "unaligned size"); assert(!UseRelocIndex, "no space allocated for reloc index yet"); @@ -64,7 +64,8 @@ CodeBlob::CodeBlob(const char* name, int header_size, int size, int frame_comple _frame_complete_offset = frame_complete; _header_size = header_size; _relocation_size = locs_size; - _instructions_offset = align_code_offset(header_size + locs_size); + _content_offset = align_code_offset(header_size + _relocation_size); + _code_offset = _content_offset; _data_offset = size; _frame_size = 0; set_oop_maps(NULL); @@ -82,7 +83,7 @@ CodeBlob::CodeBlob( int frame_size, OopMapSet* oop_maps ) { - assert(size == round_to(size, oopSize), "unaligned size"); + assert(size == round_to(size, oopSize), "unaligned size"); assert(header_size == round_to(header_size, oopSize), "unaligned size"); _name = name; @@ -90,8 +91,9 @@ CodeBlob::CodeBlob( _frame_complete_offset = frame_complete; _header_size = header_size; _relocation_size = round_to(cb->total_relocation_size(), oopSize); - _instructions_offset = align_code_offset(header_size + _relocation_size); - _data_offset = _instructions_offset + round_to(cb->total_code_size(), oopSize); + _content_offset = align_code_offset(header_size + _relocation_size); + _code_offset = _content_offset + cb->total_offset_of(cb->insts()); + _data_offset = _content_offset + round_to(cb->total_content_size(), oopSize); assert(_data_offset <= size, "codeBlob is too small"); cb->copy_code_and_locs_to(this); @@ -127,9 +129,8 @@ void CodeBlob::flush() { OopMap* CodeBlob::oop_map_for_return_address(address return_address) { - address pc = return_address ; - assert (oop_maps() != NULL, "nope"); - return oop_maps()->find_map_at_offset ((intptr_t) pc - (intptr_t) instructions_begin()); + assert(oop_maps() != NULL, "nope"); + return oop_maps()->find_map_at_offset((intptr_t) return_address - (intptr_t) code_begin()); } @@ -284,12 +285,12 @@ RuntimeStub* RuntimeStub::new_runtime_stub(const char* stub_name, jio_snprintf(stub_id, sizeof(stub_id), "RuntimeStub - %s", stub_name); if (PrintStubCode) { tty->print_cr("Decoding %s " INTPTR_FORMAT, stub_id, stub); - Disassembler::decode(stub->instructions_begin(), stub->instructions_end()); + Disassembler::decode(stub->code_begin(), stub->code_end()); } - Forte::register_stub(stub_id, stub->instructions_begin(), stub->instructions_end()); + Forte::register_stub(stub_id, stub->code_begin(), stub->code_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { - JvmtiExport::post_dynamic_code_generated(stub_name, stub->instructions_begin(), stub->instructions_end()); + JvmtiExport::post_dynamic_code_generated(stub_name, stub->code_begin(), stub->code_end()); } } @@ -355,17 +356,15 @@ DeoptimizationBlob* DeoptimizationBlob::create( // Do not hold the CodeCache lock during name formatting. if (blob != NULL) { char blob_id[256]; - jio_snprintf(blob_id, sizeof(blob_id), "DeoptimizationBlob@" PTR_FORMAT, blob->instructions_begin()); + jio_snprintf(blob_id, sizeof(blob_id), "DeoptimizationBlob@" PTR_FORMAT, blob->code_begin()); if (PrintStubCode) { tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob); - Disassembler::decode(blob->instructions_begin(), blob->instructions_end()); + Disassembler::decode(blob->code_begin(), blob->code_end()); } - Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); + Forte::register_stub(blob_id, blob->code_begin(), blob->code_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { - JvmtiExport::post_dynamic_code_generated("DeoptimizationBlob", - blob->instructions_begin(), - blob->instructions_end()); + JvmtiExport::post_dynamic_code_generated("DeoptimizationBlob", blob->code_begin(), blob->code_end()); } } @@ -412,17 +411,15 @@ UncommonTrapBlob* UncommonTrapBlob::create( // Do not hold the CodeCache lock during name formatting. if (blob != NULL) { char blob_id[256]; - jio_snprintf(blob_id, sizeof(blob_id), "UncommonTrapBlob@" PTR_FORMAT, blob->instructions_begin()); + jio_snprintf(blob_id, sizeof(blob_id), "UncommonTrapBlob@" PTR_FORMAT, blob->code_begin()); if (PrintStubCode) { tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob); - Disassembler::decode(blob->instructions_begin(), blob->instructions_end()); + Disassembler::decode(blob->code_begin(), blob->code_end()); } - Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); + Forte::register_stub(blob_id, blob->code_begin(), blob->code_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { - JvmtiExport::post_dynamic_code_generated("UncommonTrapBlob", - blob->instructions_begin(), - blob->instructions_end()); + JvmtiExport::post_dynamic_code_generated("UncommonTrapBlob", blob->code_begin(), blob->code_end()); } } @@ -471,17 +468,15 @@ ExceptionBlob* ExceptionBlob::create( // We do not need to hold the CodeCache lock during name formatting if (blob != NULL) { char blob_id[256]; - jio_snprintf(blob_id, sizeof(blob_id), "ExceptionBlob@" PTR_FORMAT, blob->instructions_begin()); + jio_snprintf(blob_id, sizeof(blob_id), "ExceptionBlob@" PTR_FORMAT, blob->code_begin()); if (PrintStubCode) { tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob); - Disassembler::decode(blob->instructions_begin(), blob->instructions_end()); + Disassembler::decode(blob->code_begin(), blob->code_end()); } - Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); + Forte::register_stub(blob_id, blob->code_begin(), blob->code_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { - JvmtiExport::post_dynamic_code_generated("ExceptionBlob", - blob->instructions_begin(), - blob->instructions_end()); + JvmtiExport::post_dynamic_code_generated("ExceptionBlob", blob->code_begin(), blob->code_end()); } } @@ -529,17 +524,15 @@ SafepointBlob* SafepointBlob::create( // We do not need to hold the CodeCache lock during name formatting. if (blob != NULL) { char blob_id[256]; - jio_snprintf(blob_id, sizeof(blob_id), "SafepointBlob@" PTR_FORMAT, blob->instructions_begin()); + jio_snprintf(blob_id, sizeof(blob_id), "SafepointBlob@" PTR_FORMAT, blob->code_begin()); if (PrintStubCode) { tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob); - Disassembler::decode(blob->instructions_begin(), blob->instructions_end()); + Disassembler::decode(blob->code_begin(), blob->code_end()); } - Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end()); + Forte::register_stub(blob_id, blob->code_begin(), blob->code_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { - JvmtiExport::post_dynamic_code_generated("SafepointBlob", - blob->instructions_begin(), - blob->instructions_end()); + JvmtiExport::post_dynamic_code_generated("SafepointBlob", blob->code_begin(), blob->code_end()); } } diff --git a/hotspot/src/share/vm/code/codeBlob.hpp b/hotspot/src/share/vm/code/codeBlob.hpp index 28cd68aa6ae..9b08c3dc880 100644 --- a/hotspot/src/share/vm/code/codeBlob.hpp +++ b/hotspot/src/share/vm/code/codeBlob.hpp @@ -35,7 +35,8 @@ // Layout: // - header // - relocation -// - instruction space +// - content space +// - instruction space // - data space class DeoptimizationBlob; @@ -48,7 +49,8 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC { int _size; // total size of CodeBlob in bytes int _header_size; // size of header (depends on subclass) int _relocation_size; // size of relocation - int _instructions_offset; // offset to where instructions region begins + int _content_offset; // offset to where content region begins (this includes consts, insts, stubs) + int _code_offset; // offset to where instructions region begins (this includes insts, stubs) int _frame_complete_offset; // instruction offsets in [0.._frame_complete_offset) have // not finished setting up their frame. Beware of pc's in // that range. There is a similar range(s) on returns @@ -106,31 +108,36 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC { address header_end() const { return ((address) this) + _header_size; }; relocInfo* relocation_begin() const { return (relocInfo*) header_end(); }; relocInfo* relocation_end() const { return (relocInfo*)(header_end() + _relocation_size); } - address instructions_begin() const { return (address) header_begin() + _instructions_offset; } - address instructions_end() const { return (address) header_begin() + _data_offset; } + address content_begin() const { return (address) header_begin() + _content_offset; } + address content_end() const { return (address) header_begin() + _data_offset; } + address code_begin() const { return (address) header_begin() + _code_offset; } + address code_end() const { return (address) header_begin() + _data_offset; } address data_begin() const { return (address) header_begin() + _data_offset; } address data_end() const { return (address) header_begin() + _size; } // Offsets int relocation_offset() const { return _header_size; } - int instructions_offset() const { return _instructions_offset; } + int content_offset() const { return _content_offset; } + int code_offset() const { return _code_offset; } int data_offset() const { return _data_offset; } // Sizes int size() const { return _size; } int header_size() const { return _header_size; } int relocation_size() const { return (address) relocation_end() - (address) relocation_begin(); } - int instructions_size() const { return instructions_end() - instructions_begin(); } - int data_size() const { return data_end() - data_begin(); } + int content_size() const { return content_end() - content_begin(); } + int code_size() const { return code_end() - code_begin(); } + int data_size() const { return data_end() - data_begin(); } // Containment - bool blob_contains(address addr) const { return header_begin() <= addr && addr < data_end(); } + bool blob_contains(address addr) const { return header_begin() <= addr && addr < data_end(); } bool relocation_contains(relocInfo* addr) const{ return relocation_begin() <= addr && addr < relocation_end(); } - bool instructions_contains(address addr) const { return instructions_begin() <= addr && addr < instructions_end(); } - bool data_contains(address addr) const { return data_begin() <= addr && addr < data_end(); } - bool contains(address addr) const { return instructions_contains(addr); } - bool is_frame_complete_at(address addr) const { return instructions_contains(addr) && - addr >= instructions_begin() + _frame_complete_offset; } + bool content_contains(address addr) const { return content_begin() <= addr && addr < content_end(); } + bool code_contains(address addr) const { return code_begin() <= addr && addr < code_end(); } + bool data_contains(address addr) const { return data_begin() <= addr && addr < data_end(); } + bool contains(address addr) const { return content_contains(addr); } + bool is_frame_complete_at(address addr) const { return code_contains(addr) && + addr >= code_begin() + _frame_complete_offset; } // CodeCache support: really only used by the nmethods, but in order to get // asserts and certain bookkeeping to work in the CodeCache they are defined @@ -169,7 +176,7 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC { // Print the comment associated with offset on stream, if there is one virtual void print_block_comment(outputStream* stream, address block_begin) { - intptr_t offset = (intptr_t)(block_begin - instructions_begin()); + intptr_t offset = (intptr_t)(block_begin - code_begin()); _comments.print_block_comment(stream, offset); } @@ -286,7 +293,7 @@ class RuntimeStub: public CodeBlob { // GC support bool caller_must_gc_arguments(JavaThread* thread) const { return _caller_must_gc_arguments; } - address entry_point() { return instructions_begin(); } + address entry_point() { return code_begin(); } // GC/Verification support void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* nothing to do */ } @@ -313,13 +320,15 @@ class SingletonBlob: public CodeBlob { OopMapSet* oop_maps ) : CodeBlob(name, cb, header_size, size, CodeOffsets::frame_never_safe, frame_size, oop_maps) - {}; + {}; - bool is_alive() const { return true; } + address entry_point() { return code_begin(); } - void verify(); // does nothing - void print_on(outputStream* st) const; - void print_value_on(outputStream* st) const; + bool is_alive() const { return true; } + + void verify(); // does nothing + void print_on(outputStream* st) const; + void print_value_on(outputStream* st) const; }; @@ -376,9 +385,9 @@ class DeoptimizationBlob: public SingletonBlob { // Printing void print_value_on(outputStream* st) const; - address unpack() const { return instructions_begin() + _unpack_offset; } - address unpack_with_exception() const { return instructions_begin() + _unpack_with_exception; } - address unpack_with_reexecution() const { return instructions_begin() + _unpack_with_reexecution; } + address unpack() const { return code_begin() + _unpack_offset; } + address unpack_with_exception() const { return code_begin() + _unpack_with_exception; } + address unpack_with_reexecution() const { return code_begin() + _unpack_with_reexecution; } // Alternate entry point for C1 where the exception and issuing pc // are in JavaThread::_exception_oop and JavaThread::_exception_pc @@ -387,9 +396,9 @@ class DeoptimizationBlob: public SingletonBlob { // there may be live values in those registers during deopt. void set_unpack_with_exception_in_tls_offset(int offset) { _unpack_with_exception_in_tls = offset; - assert(contains(instructions_begin() + _unpack_with_exception_in_tls), "must be PC inside codeblob"); + assert(code_contains(code_begin() + _unpack_with_exception_in_tls), "must be PC inside codeblob"); } - address unpack_with_exception_in_tls() const { return instructions_begin() + _unpack_with_exception_in_tls; } + address unpack_with_exception_in_tls() const { return code_begin() + _unpack_with_exception_in_tls; } }; diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index 485aff8123a..b02f142ccfc 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -76,14 +76,14 @@ class CodeBlob_sizes { relocation_size += cb->relocation_size(); if (cb->is_nmethod()) { nmethod* nm = cb->as_nmethod_or_null(); - code_size += nm->code_size(); + code_size += nm->insts_size(); stub_size += nm->stub_size(); scopes_oop_size += nm->oops_size(); scopes_data_size += nm->scopes_data_size(); scopes_pcs_size += nm->scopes_pcs_size(); } else { - code_size += cb->instructions_size(); + code_size += cb->code_size(); } } }; @@ -210,7 +210,7 @@ void CodeCache::commit(CodeBlob* cb) { } // flush the hardware I-cache - ICache::invalidate_range(cb->instructions_begin(), cb->instructions_size()); + ICache::invalidate_range(cb->content_begin(), cb->content_size()); } @@ -804,8 +804,8 @@ void CodeCache::print_internals() { if(nm->method() != NULL && nm->is_java_method()) { nmethodJava++; - if(nm->code_size() > maxCodeSize) { - maxCodeSize = nm->code_size(); + if (nm->insts_size() > maxCodeSize) { + maxCodeSize = nm->insts_size(); } } } else if (cb->is_runtime_stub()) { @@ -830,7 +830,7 @@ void CodeCache::print_internals() { if (cb->is_nmethod()) { nmethod* nm = (nmethod*)cb; if(nm->is_java_method()) { - buckets[nm->code_size() / bucketSize]++; + buckets[nm->insts_size() / bucketSize]++; } } } @@ -896,11 +896,11 @@ void CodeCache::print() { FOR_ALL_BLOBS(p) { if (p->is_alive()) { number_of_blobs++; - code_size += p->instructions_size(); + code_size += p->code_size(); OopMapSet* set = p->oop_maps(); if (set != NULL) { number_of_oop_maps += set->size(); - map_size += set->heap_size(); + map_size += set->heap_size(); } } } diff --git a/hotspot/src/share/vm/code/exceptionHandlerTable.cpp b/hotspot/src/share/vm/code/exceptionHandlerTable.cpp index 8ad6592b4fd..12cc9cdf7bf 100644 --- a/hotspot/src/share/vm/code/exceptionHandlerTable.cpp +++ b/hotspot/src/share/vm/code/exceptionHandlerTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -219,8 +219,8 @@ void ImplicitExceptionTable::copy_to( nmethod* nm ) { void ImplicitExceptionTable::verify(nmethod *nm) const { for (uint i = 0; i < len(); i++) { - if ((*adr(i) > (unsigned int)nm->code_size()) || - (*(adr(i)+1) > (unsigned int)nm->code_size())) + if ((*adr(i) > (unsigned int)nm->insts_size()) || + (*(adr(i)+1) > (unsigned int)nm->insts_size())) fatal(err_msg("Invalid offset in ImplicitExceptionTable at " PTR_FORMAT, _data)); } } diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index af0f1833368..9da564d277e 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -87,9 +87,9 @@ struct nmethod_stats_struct { int nmethod_count; int total_size; int relocation_size; - int code_size; - int stub_size; int consts_size; + int insts_size; + int stub_size; int scopes_data_size; int scopes_pcs_size; int dependencies_size; @@ -101,9 +101,9 @@ struct nmethod_stats_struct { nmethod_count += 1; total_size += nm->size(); relocation_size += nm->relocation_size(); - code_size += nm->code_size(); - stub_size += nm->stub_size(); consts_size += nm->consts_size(); + insts_size += nm->insts_size(); + stub_size += nm->stub_size(); oops_size += nm->oops_size(); scopes_data_size += nm->scopes_data_size(); scopes_pcs_size += nm->scopes_pcs_size(); @@ -116,9 +116,9 @@ struct nmethod_stats_struct { tty->print_cr("Statistics for %d bytecoded nmethods:", nmethod_count); if (total_size != 0) tty->print_cr(" total in heap = %d", total_size); if (relocation_size != 0) tty->print_cr(" relocation = %d", relocation_size); - if (code_size != 0) tty->print_cr(" main code = %d", code_size); - if (stub_size != 0) tty->print_cr(" stub code = %d", stub_size); if (consts_size != 0) tty->print_cr(" constants = %d", consts_size); + if (insts_size != 0) tty->print_cr(" main code = %d", insts_size); + if (stub_size != 0) tty->print_cr(" stub code = %d", stub_size); if (oops_size != 0) tty->print_cr(" oops = %d", oops_size); if (scopes_data_size != 0) tty->print_cr(" scopes data = %d", scopes_data_size); if (scopes_pcs_size != 0) tty->print_cr(" scopes pcs = %d", scopes_pcs_size); @@ -130,13 +130,13 @@ struct nmethod_stats_struct { int native_nmethod_count; int native_total_size; int native_relocation_size; - int native_code_size; + int native_insts_size; int native_oops_size; void note_native_nmethod(nmethod* nm) { native_nmethod_count += 1; native_total_size += nm->size(); native_relocation_size += nm->relocation_size(); - native_code_size += nm->code_size(); + native_insts_size += nm->insts_size(); native_oops_size += nm->oops_size(); } void print_native_nmethod_stats() { @@ -144,7 +144,7 @@ struct nmethod_stats_struct { tty->print_cr("Statistics for %d native nmethods:", native_nmethod_count); if (native_total_size != 0) tty->print_cr(" N. total size = %d", native_total_size); if (native_relocation_size != 0) tty->print_cr(" N. relocation = %d", native_relocation_size); - if (native_code_size != 0) tty->print_cr(" N. main code = %d", native_code_size); + if (native_insts_size != 0) tty->print_cr(" N. main code = %d", native_insts_size); if (native_oops_size != 0) tty->print_cr(" N. oops = %d", native_oops_size); } @@ -404,9 +404,9 @@ void nmethod::add_handler_for_exception_and_pc(Handle exception, address pc, add int nmethod::total_size() const { return - code_size() + - stub_size() + consts_size() + + insts_size() + + stub_size() + scopes_data_size() + scopes_pcs_size() + handler_table_size() + @@ -433,6 +433,10 @@ void nmethod::init_defaults() { _unload_reported = false; // jvmti state NOT_PRODUCT(_has_debug_info = false); +#ifdef ASSERT + _oops_are_stale = false; +#endif + _oops_do_mark_link = NULL; _jmethod_id = NULL; _osr_link = NULL; @@ -614,8 +618,8 @@ nmethod::nmethod( _deoptimize_mh_offset = 0; _orig_pc_offset = 0; - _stub_offset = data_offset(); _consts_offset = data_offset(); + _stub_offset = data_offset(); _oops_offset = data_offset(); _scopes_data_offset = _oops_offset + round_to(code_buffer->total_oop_size(), oopSize); _scopes_pcs_offset = _scopes_data_offset; @@ -625,8 +629,8 @@ nmethod::nmethod( _nmethod_end_offset = _nul_chk_table_offset; _compile_id = 0; // default _comp_level = CompLevel_none; - _entry_point = instructions_begin(); - _verified_entry_point = instructions_begin() + offsets->value(CodeOffsets::Verified_Entry); + _entry_point = code_begin() + offsets->value(CodeOffsets::Entry); + _verified_entry_point = code_begin() + offsets->value(CodeOffsets::Verified_Entry); _osr_entry_point = NULL; _exception_cache = NULL; _pc_desc_cache.reset_to(NULL); @@ -692,8 +696,8 @@ nmethod::nmethod( _unwind_handler_offset = -1; _trap_offset = offsets->value(CodeOffsets::Dtrace_trap); _orig_pc_offset = 0; - _stub_offset = data_offset(); _consts_offset = data_offset(); + _stub_offset = data_offset(); _oops_offset = data_offset(); _scopes_data_offset = _oops_offset + round_to(code_buffer->total_oop_size(), oopSize); _scopes_pcs_offset = _scopes_data_offset; @@ -703,8 +707,8 @@ nmethod::nmethod( _nmethod_end_offset = _nul_chk_table_offset; _compile_id = 0; // default _comp_level = CompLevel_none; - _entry_point = instructions_begin(); - _verified_entry_point = instructions_begin() + offsets->value(CodeOffsets::Verified_Entry); + _entry_point = code_begin() + offsets->value(CodeOffsets::Entry); + _verified_entry_point = code_begin() + offsets->value(CodeOffsets::Verified_Entry); _osr_entry_point = NULL; _exception_cache = NULL; _pc_desc_cache.reset_to(NULL); @@ -783,18 +787,25 @@ nmethod::nmethod( _comp_level = comp_level; _compiler = compiler; _orig_pc_offset = orig_pc_offset; - _stub_offset = instructions_offset() + code_buffer->total_offset_of(code_buffer->stubs()->start()); + + // Section offsets + _consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts()); + _stub_offset = content_offset() + code_buffer->total_offset_of(code_buffer->stubs()); // Exception handler and deopt handler are in the stub section - _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); - _deoptimize_offset = _stub_offset + offsets->value(CodeOffsets::Deopt); - _deoptimize_mh_offset = _stub_offset + offsets->value(CodeOffsets::DeoptMH); - if (offsets->value(CodeOffsets::UnwindHandler) != -1) { - _unwind_handler_offset = instructions_offset() + offsets->value(CodeOffsets::UnwindHandler); + _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); + _deoptimize_offset = _stub_offset + offsets->value(CodeOffsets::Deopt); + if (has_method_handle_invokes()) { + _deoptimize_mh_offset = _stub_offset + offsets->value(CodeOffsets::DeoptMH); } else { - _unwind_handler_offset = -1; + _deoptimize_mh_offset = -1; } - _consts_offset = instructions_offset() + code_buffer->total_offset_of(code_buffer->consts()->start()); + if (offsets->value(CodeOffsets::UnwindHandler) != -1) { + _unwind_handler_offset = code_offset() + offsets->value(CodeOffsets::UnwindHandler); + } else { + _unwind_handler_offset = -1; + } + _oops_offset = data_offset(); _scopes_data_offset = _oops_offset + round_to(code_buffer->total_oop_size (), oopSize); _scopes_pcs_offset = _scopes_data_offset + round_to(debug_info->data_size (), oopSize); @@ -803,9 +814,9 @@ nmethod::nmethod( _nul_chk_table_offset = _handler_table_offset + round_to(handler_table->size_in_bytes(), oopSize); _nmethod_end_offset = _nul_chk_table_offset + round_to(nul_chk_table->size_in_bytes(), oopSize); - _entry_point = instructions_begin(); - _verified_entry_point = instructions_begin() + offsets->value(CodeOffsets::Verified_Entry); - _osr_entry_point = instructions_begin() + offsets->value(CodeOffsets::OSR_Entry); + _entry_point = code_begin() + offsets->value(CodeOffsets::Entry); + _verified_entry_point = code_begin() + offsets->value(CodeOffsets::Verified_Entry); + _osr_entry_point = code_begin() + offsets->value(CodeOffsets::OSR_Entry); _exception_cache = NULL; _pc_desc_cache.reset_to(scopes_pcs_begin()); @@ -856,9 +867,9 @@ void nmethod::log_identity(xmlStream* log) const { if (compiler() != NULL) { log->print(" compiler='%s'", compiler()->name()); } -#ifdef TIERED - log->print(" level='%d'", comp_level()); -#endif // TIERED + if (TieredCompilation) { + log->print(" level='%d'", comp_level()); + } } @@ -874,14 +885,13 @@ void nmethod::log_new_nmethod() const { HandleMark hm; xtty->begin_elem("nmethod"); log_identity(xtty); - xtty->print(" entry='" INTPTR_FORMAT "' size='%d'", - instructions_begin(), size()); + xtty->print(" entry='" INTPTR_FORMAT "' size='%d'", code_begin(), size()); xtty->print(" address='" INTPTR_FORMAT "'", (intptr_t) this); LOG_OFFSET(xtty, relocation); - LOG_OFFSET(xtty, code); - LOG_OFFSET(xtty, stub); LOG_OFFSET(xtty, consts); + LOG_OFFSET(xtty, insts); + LOG_OFFSET(xtty, stub); LOG_OFFSET(xtty, scopes_data); LOG_OFFSET(xtty, scopes_pcs); LOG_OFFSET(xtty, dependencies); @@ -898,35 +908,73 @@ void nmethod::log_new_nmethod() const { #undef LOG_OFFSET +void nmethod::print_compilation(outputStream *st, const char *method_name, const char *title, + methodOop method, bool is_blocking, int compile_id, int bci, int comp_level) { + bool is_synchronized = false, has_xhandler = false, is_native = false; + int code_size = -1; + if (method != NULL) { + is_synchronized = method->is_synchronized(); + has_xhandler = method->has_exception_handler(); + is_native = method->is_native(); + code_size = method->code_size(); + } + // print compilation number + st->print("%7d %3d", (int)tty->time_stamp().milliseconds(), compile_id); + + // print method attributes + const bool is_osr = bci != InvocationEntryBci; + const char blocking_char = is_blocking ? 'b' : ' '; + const char compile_type = is_osr ? '%' : ' '; + const char sync_char = is_synchronized ? 's' : ' '; + const char exception_char = has_xhandler ? '!' : ' '; + const char native_char = is_native ? 'n' : ' '; + st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char); + if (TieredCompilation) { + st->print("%d ", comp_level); + } + + // print optional title + bool do_nl = false; + if (title != NULL) { + int tlen = (int) strlen(title); + bool do_nl = false; + if (tlen > 0 && title[tlen-1] == '\n') { tlen--; do_nl = true; } + st->print("%.*s", tlen, title); + } else { + do_nl = true; + } + + // print method name string if given + if (method_name != NULL) { + st->print(method_name); + } else { + // otherwise as the method to print itself + if (method != NULL && !Universe::heap()->is_gc_active()) { + method->print_short_name(st); + } else { + st->print("(method)"); + } + } + + if (method != NULL) { + // print osr_bci if any + if (is_osr) st->print(" @ %d", bci); + // print method size + st->print(" (%d bytes)", code_size); + } + if (do_nl) st->cr(); +} + // Print out more verbose output usually for a newly created nmethod. void nmethod::print_on(outputStream* st, const char* title) const { if (st != NULL) { ttyLocker ttyl; - // Print a little tag line that looks like +PrintCompilation output: - int tlen = (int) strlen(title); - bool do_nl = false; - if (tlen > 0 && title[tlen-1] == '\n') { tlen--; do_nl = true; } - st->print("%3d%c %.*s", - compile_id(), - is_osr_method() ? '%' : - method() != NULL && - is_native_method() ? 'n' : ' ', - tlen, title); -#ifdef TIERED - st->print(" (%d) ", comp_level()); -#endif // TIERED + print_compilation(st, /*method_name*/NULL, title, + method(), /*is_blocking*/false, + compile_id(), + is_osr_method() ? osr_entry_bci() : InvocationEntryBci, + comp_level()); if (WizardMode) st->print(" (" INTPTR_FORMAT ")", this); - if (Universe::heap()->is_gc_active() && method() != NULL) { - st->print("(method)"); - } else if (method() != NULL) { - method()->print_short_name(st); - if (is_osr_method()) - st->print(" @ %d", osr_entry_bci()); - if (method()->code_size() > 0) - st->print(" (%d bytes)", method()->code_size()); - } - - if (do_nl) st->cr(); } } @@ -1127,6 +1175,7 @@ bool nmethod::can_not_entrant_be_converted() { } void nmethod::inc_decompile_count() { + if (!is_compiled_by_c2()) return; // Could be gated by ProfileTraps, but do not bother... methodOop m = method(); if (m == NULL) return; @@ -1230,11 +1279,10 @@ void nmethod::log_state_change() const { bool nmethod::make_not_entrant_or_zombie(unsigned int state) { assert(state == zombie || state == not_entrant, "must be zombie or not_entrant"); - bool was_alive = false; - // Make sure neither the nmethod nor the method is flushed in case of a safepoint in code below. nmethodLocker nml(this); methodHandle the_method(method()); + No_Safepoint_Verifier nsv; { // If the method is already zombie there is nothing to do @@ -1303,13 +1351,27 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { // state will be flushed later when the transition to zombie // happens or they get unloaded. if (state == zombie) { - // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event - // and it hasn't already been reported for this nmethod then report it now. - // (the event may have been reported earilier if the GC marked it for unloading). - post_compiled_method_unload(); + { + // Flushing dependecies must be done before any possible + // safepoint can sneak in, otherwise the oops used by the + // dependency logic could have become stale. + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + flush_dependencies(NULL); + } - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - flush_dependencies(NULL); + { + // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event + // and it hasn't already been reported for this nmethod then report it now. + // (the event may have been reported earilier if the GC marked it for unloading). + Pause_No_Safepoint_Verifier pnsv(&nsv); + post_compiled_method_unload(); + } + +#ifdef ASSERT + // It's no longer safe to access the oops section since zombie + // nmethods aren't scanned for GC. + _oops_are_stale = true; +#endif } else { assert(state == not_entrant, "other cases may need to be handled differently"); } @@ -1443,7 +1505,7 @@ void nmethod::post_compiled_method_load_event() { moop->name()->utf8_length(), moop->signature()->bytes(), moop->signature()->utf8_length(), - code_begin(), code_size()); + insts_begin(), insts_size()); if (JvmtiExport::should_post_compiled_method_load() || JvmtiExport::should_post_compiled_method_unload()) { @@ -1485,7 +1547,7 @@ void nmethod::post_compiled_method_unload() { if (_jmethod_id != NULL && JvmtiExport::should_post_compiled_method_unload()) { assert(!unload_reported(), "already unloaded"); HandleMark hm; - JvmtiExport::post_compiled_method_unload(_jmethod_id, code_begin()); + JvmtiExport::post_compiled_method_unload(_jmethod_id, insts_begin()); } // The JVMTI CompiledMethodUnload event can be enabled or disabled at @@ -1837,7 +1899,7 @@ void nmethod::copy_scopes_pcs(PcDesc* pcs, int count) { // Adjust the final sentinel downward. PcDesc* last_pc = &scopes_pcs_begin()[count-1]; assert(last_pc->pc_offset() == PcDesc::upper_offset_limit, "sanity"); - last_pc->set_pc_offset(instructions_size() + 1); + last_pc->set_pc_offset(content_size() + 1); for (; last_pc + 1 < scopes_pcs_end(); last_pc += 1) { // Fill any rounding gaps with copies of the last record. last_pc[1] = last_pc[0]; @@ -1877,7 +1939,7 @@ static PcDesc* linear_search(nmethod* nm, int pc_offset, bool approximate) { // Finds a PcDesc with real-pc equal to "pc" PcDesc* nmethod::find_pc_desc_internal(address pc, bool approximate) { - address base_address = instructions_begin(); + address base_address = code_begin(); if ((pc < base_address) || (pc - base_address) >= (ptrdiff_t) PcDesc::upper_offset_limit) { return NULL; // PC is wildly out of range @@ -2025,7 +2087,7 @@ bool nmethod::is_dependent_on_method(methodOop dependee) { bool nmethod::is_patchable_at(address instr_addr) { - assert (code_contains(instr_addr), "wrong nmethod used"); + assert(insts_contains(instr_addr), "wrong nmethod used"); if (is_zombie()) { // a zombie may never be patched return false; @@ -2037,7 +2099,7 @@ bool nmethod::is_patchable_at(address instr_addr) { address nmethod::continuation_for_implicit_exception(address pc) { // Exception happened outside inline-cache check code => we are inside // an active nmethod => use cpc to determine a return address - int exception_offset = pc - instructions_begin(); + int exception_offset = pc - code_begin(); int cont_offset = ImplicitExceptionTable(this).at( exception_offset ); #ifdef ASSERT if (cont_offset == 0) { @@ -2058,7 +2120,7 @@ address nmethod::continuation_for_implicit_exception(address pc) { // Let the normal error handling report the exception return NULL; } - return instructions_begin() + cont_offset; + return code_begin() + cont_offset; } @@ -2317,18 +2379,18 @@ void nmethod::print() const { relocation_begin(), relocation_end(), relocation_size()); - if (code_size () > 0) tty->print_cr(" main code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - code_begin(), - code_end(), - code_size()); - if (stub_size () > 0) tty->print_cr(" stub code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - stub_begin(), - stub_end(), - stub_size()); if (consts_size () > 0) tty->print_cr(" constants [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", consts_begin(), consts_end(), consts_size()); + if (insts_size () > 0) tty->print_cr(" main code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", + insts_begin(), + insts_end(), + insts_size()); + if (stub_size () > 0) tty->print_cr(" stub code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", + stub_begin(), + stub_end(), + stub_size()); if (oops_size () > 0) tty->print_cr(" oops [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", oops_begin(), oops_end(), @@ -2353,10 +2415,6 @@ void nmethod::print() const { nul_chk_table_begin(), nul_chk_table_end(), nul_chk_table_size()); - if (oops_size () > 0) tty->print_cr(" oops [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - oops_begin(), - oops_end(), - oops_size()); } void nmethod::print_code() { @@ -2590,7 +2648,7 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, // First, find an oopmap in (begin, end]. // We use the odd half-closed interval so that oop maps and scope descs // which are tied to the byte after a call are printed with the call itself. - address base = instructions_begin(); + address base = code_begin(); OopMapSet* oms = oop_maps(); if (oms != NULL) { for (int i = 0, imax = oms->size(); i < imax; i++) { @@ -2678,10 +2736,10 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, st->move_to(column); st->print("; {%s}", str); } - int cont_offset = ImplicitExceptionTable(this).at(begin - instructions_begin()); + int cont_offset = ImplicitExceptionTable(this).at(begin - code_begin()); if (cont_offset != 0) { st->move_to(column); - st->print("; implicit exception: dispatches to " INTPTR_FORMAT, instructions_begin() + cont_offset); + st->print("; implicit exception: dispatches to " INTPTR_FORMAT, code_begin() + cont_offset); } } @@ -2715,7 +2773,7 @@ void nmethod::print_handler_table() { } void nmethod::print_nul_chk_table() { - ImplicitExceptionTable(this).print(instructions_begin()); + ImplicitExceptionTable(this).print(code_begin()); } void nmethod::print_statistics() { diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index b57cb5e3dc7..52a09c91029 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -143,8 +143,8 @@ class nmethod : public CodeBlob { #ifdef HAVE_DTRACE_H int _trap_offset; #endif // def HAVE_DTRACE_H - int _stub_offset; int _consts_offset; + int _stub_offset; int _oops_offset; // offset to where embedded oop table begins (inside data) int _scopes_data_offset; int _scopes_pcs_offset; @@ -177,6 +177,10 @@ class nmethod : public CodeBlob { // Protected by Patching_lock unsigned char _state; // {alive, not_entrant, zombie, unloaded) +#ifdef ASSERT + bool _oops_are_stale; // indicates that it's no longer safe to access oops section +#endif + enum { alive = 0, not_entrant = 1, // uncommon trap has happened but activations may still exist zombie = 2, @@ -308,7 +312,7 @@ class nmethod : public CodeBlob { int frame_size); int trap_offset() const { return _trap_offset; } - address trap_address() const { return code_begin() + _trap_offset; } + address trap_address() const { return insts_begin() + _trap_offset; } #endif // def HAVE_DTRACE_H @@ -332,16 +336,16 @@ class nmethod : public CodeBlob { bool is_compiled_by_shark() const; // boundaries for different parts - address code_begin () const { return _entry_point; } - address code_end () const { return header_begin() + _stub_offset ; } + address consts_begin () const { return header_begin() + _consts_offset ; } + address consts_end () const { return header_begin() + code_offset() ; } + address insts_begin () const { return header_begin() + code_offset() ; } + address insts_end () const { return header_begin() + _stub_offset ; } + address stub_begin () const { return header_begin() + _stub_offset ; } + address stub_end () const { return header_begin() + _oops_offset ; } address exception_begin () const { return header_begin() + _exception_offset ; } address deopt_handler_begin () const { return header_begin() + _deoptimize_offset ; } address deopt_mh_handler_begin() const { return header_begin() + _deoptimize_mh_offset ; } address unwind_handler_begin () const { return _unwind_handler_offset != -1 ? (header_begin() + _unwind_handler_offset) : NULL; } - address stub_begin () const { return header_begin() + _stub_offset ; } - address stub_end () const { return header_begin() + _consts_offset ; } - address consts_begin () const { return header_begin() + _consts_offset ; } - address consts_end () const { return header_begin() + _oops_offset ; } oop* oops_begin () const { return (oop*) (header_begin() + _oops_offset) ; } oop* oops_end () const { return (oop*) (header_begin() + _scopes_data_offset) ; } @@ -357,9 +361,9 @@ class nmethod : public CodeBlob { address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; } // Sizes - int code_size () const { return code_end () - code_begin (); } - int stub_size () const { return stub_end () - stub_begin (); } int consts_size () const { return consts_end () - consts_begin (); } + int insts_size () const { return insts_end () - insts_begin (); } + int stub_size () const { return stub_end () - stub_begin (); } int oops_size () const { return (address) oops_end () - (address) oops_begin (); } int scopes_data_size () const { return scopes_data_end () - scopes_data_begin (); } int scopes_pcs_size () const { return (intptr_t) scopes_pcs_end () - (intptr_t) scopes_pcs_begin (); } @@ -370,9 +374,9 @@ class nmethod : public CodeBlob { int total_size () const; // Containment - bool code_contains (address addr) const { return code_begin () <= addr && addr < code_end (); } - bool stub_contains (address addr) const { return stub_begin () <= addr && addr < stub_end (); } bool consts_contains (address addr) const { return consts_begin () <= addr && addr < consts_end (); } + bool insts_contains (address addr) const { return insts_begin () <= addr && addr < insts_end (); } + bool stub_contains (address addr) const { return stub_begin () <= addr && addr < stub_end (); } bool oops_contains (oop* addr) const { return oops_begin () <= addr && addr < oops_end (); } bool scopes_data_contains (address addr) const { return scopes_data_begin () <= addr && addr < scopes_data_end (); } bool scopes_pcs_contains (PcDesc* addr) const { return scopes_pcs_begin () <= addr && addr < scopes_pcs_end (); } @@ -434,6 +438,7 @@ class nmethod : public CodeBlob { oop* oop_addr_at(int index) const { // for GC // relocation indexes are biased by 1 (because 0 is reserved) assert(index > 0 && index <= oops_size(), "must be a valid non-zero index"); + assert(!_oops_are_stale, "oops are stale"); return &oops_begin()[index - 1]; } @@ -501,7 +506,7 @@ public: void clear_inline_caches(); void cleanup_inline_caches(); bool inlinecache_check_contains(address addr) const { - return (addr >= instructions_begin() && addr < verified_entry_point()); + return (addr >= code_begin() && addr < verified_entry_point()); } // unlink and deallocate this nmethod @@ -554,7 +559,7 @@ public: PcDesc* find_pc_desc(address pc, bool approximate) { PcDesc* desc = _pc_desc_cache.last_pc_desc(); - if (desc != NULL && desc->pc_offset() == pc - instructions_begin()) { + if (desc != NULL && desc->pc_offset() == pc - code_begin()) { return desc; } return find_pc_desc_internal(pc, approximate); @@ -594,6 +599,10 @@ public: void verify_scopes(); void verify_interrupt_point(address interrupt_point); + // print compilation helper + static void print_compilation(outputStream *st, const char *method_name, const char *title, + methodOop method, bool is_blocking, int compile_id, int bci, int comp_level); + // printing support void print() const; void print_code(); diff --git a/hotspot/src/share/vm/code/pcDesc.cpp b/hotspot/src/share/vm/code/pcDesc.cpp index 9e063fb16af..b8a9eb47543 100644 --- a/hotspot/src/share/vm/code/pcDesc.cpp +++ b/hotspot/src/share/vm/code/pcDesc.cpp @@ -34,7 +34,7 @@ PcDesc::PcDesc(int pc_offset, int scope_decode_offset, int obj_decode_offset) { } address PcDesc::real_pc(const nmethod* code) const { - return code->instructions_begin() + pc_offset(); + return code->code_begin() + pc_offset(); } void PcDesc::print(nmethod* code) { diff --git a/hotspot/src/share/vm/code/relocInfo.cpp b/hotspot/src/share/vm/code/relocInfo.cpp index 6afb3c54d75..a21f34642e4 100644 --- a/hotspot/src/share/vm/code/relocInfo.cpp +++ b/hotspot/src/share/vm/code/relocInfo.cpp @@ -128,13 +128,20 @@ void RelocIterator::initialize(nmethod* nm, address begin, address limit) { _code = nm; _current = nm->relocation_begin() - 1; _end = nm->relocation_end(); - _addr = (address) nm->instructions_begin(); + _addr = nm->content_begin(); + + // Initialize code sections. + _section_start[CodeBuffer::SECT_CONSTS] = nm->consts_begin(); + _section_start[CodeBuffer::SECT_INSTS ] = nm->insts_begin() ; + _section_start[CodeBuffer::SECT_STUBS ] = nm->stub_begin() ; + + _section_end [CodeBuffer::SECT_CONSTS] = nm->consts_end() ; + _section_end [CodeBuffer::SECT_INSTS ] = nm->insts_end() ; + _section_end [CodeBuffer::SECT_STUBS ] = nm->stub_end() ; assert(!has_current(), "just checking"); - address code_end = nm->instructions_end(); - - assert(begin == NULL || begin >= nm->instructions_begin(), "in bounds"); - // FIX THIS assert(limit == NULL || limit <= code_end, "in bounds"); + assert(begin == NULL || begin >= nm->code_begin(), "in bounds"); + assert(limit == NULL || limit <= nm->code_end(), "in bounds"); set_limits(begin, limit); } @@ -148,9 +155,11 @@ RelocIterator::RelocIterator(CodeSection* cs, address begin, address limit) { _code = NULL; // Not cb->blob(); CodeBuffer* cb = cs->outer(); - assert((int)SECT_LIMIT == CodeBuffer::SECT_LIMIT, "my copy must be equal"); - for (int n = 0; n < (int)SECT_LIMIT; n++) { - _section_start[n] = cb->code_section(n)->start(); + assert((int) SECT_LIMIT == CodeBuffer::SECT_LIMIT, "my copy must be equal"); + for (int n = (int) CodeBuffer::SECT_FIRST; n < (int) CodeBuffer::SECT_LIMIT; n++) { + CodeSection* cs = cb->code_section(n); + _section_start[n] = cs->start(); + _section_end [n] = cs->end(); } assert(!has_current(), "just checking"); @@ -168,6 +177,12 @@ struct RelocIndexEntry { }; +bool RelocIterator::addr_in_const() const { + const int n = CodeBuffer::SECT_CONSTS; + return section_start(n) <= addr() && addr() < section_end(n); +} + + static inline int num_cards(int code_size) { return (code_size-1) / indexCardSize; } @@ -267,7 +282,7 @@ void RelocIterator::set_limits(address begin, address limit) { // skip ahead RelocIndexEntry* index = (RelocIndexEntry*)_end; RelocIndexEntry* index_limit = (RelocIndexEntry*)((address)index + index_size); - assert(_addr == _code->instructions_begin(), "_addr must be unadjusted"); + assert(_addr == _code->code_begin(), "_addr must be unadjusted"); int card = (begin - _addr) / indexCardSize; if (card > 0) { if (index+card-1 < index_limit) index += card-1; @@ -362,31 +377,12 @@ void RelocIterator::advance_over_prefix() { } -address RelocIterator::compute_section_start(int n) const { -// This routine not only computes a section start, but also -// memoizes it for later. -#define CACHE ((RelocIterator*)this)->_section_start[n] - CodeBlob* cb = code(); - guarantee(cb != NULL, "must have a code blob"); - if (n == CodeBuffer::SECT_INSTS) - return CACHE = cb->instructions_begin(); - assert(cb->is_nmethod(), "only nmethods have these sections"); - nmethod* nm = (nmethod*) cb; - address res = NULL; - switch (n) { - case CodeBuffer::SECT_STUBS: - res = nm->stub_begin(); - break; - case CodeBuffer::SECT_CONSTS: - res = nm->consts_begin(); - break; - default: - ShouldNotReachHere(); +void RelocIterator::initialize_misc() { + set_has_current(false); + for (int i = (int) CodeBuffer::SECT_FIRST; i < (int) CodeBuffer::SECT_LIMIT; i++) { + _section_start[i] = NULL; // these will be lazily computed, if needed + _section_end [i] = NULL; } - assert(nm->contains(res) || res == nm->instructions_end(), "tame pointer"); - CACHE = res; - return res; -#undef CACHE } diff --git a/hotspot/src/share/vm/code/relocInfo.hpp b/hotspot/src/share/vm/code/relocInfo.hpp index 7bb1887376b..116a097f395 100644 --- a/hotspot/src/share/vm/code/relocInfo.hpp +++ b/hotspot/src/share/vm/code/relocInfo.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -502,8 +502,7 @@ class RelocationHolder VALUE_OBJ_CLASS_SPEC { // } class RelocIterator : public StackObj { - enum { SECT_CONSTS = 2, - SECT_LIMIT = 3 }; // must be equal to CodeBuffer::SECT_LIMIT + enum { SECT_LIMIT = 3 }; // must be equal to CodeBuffer::SECT_LIMIT, checked in ctor friend class Relocation; friend class relocInfo; // for change_reloc_info_for_address only typedef relocInfo::relocType relocType; @@ -521,6 +520,7 @@ class RelocIterator : public StackObj { // Base addresses needed to compute targets of section_word_type relocs. address _section_start[SECT_LIMIT]; + address _section_end [SECT_LIMIT]; void set_has_current(bool b) { _datalen = !b ? -1 : 0; @@ -540,14 +540,7 @@ class RelocIterator : public StackObj { void advance_over_prefix(); // helper method - void initialize_misc() { - set_has_current(false); - for (int i = 0; i < SECT_LIMIT; i++) { - _section_start[i] = NULL; // these will be lazily computed, if needed - } - } - - address compute_section_start(int n) const; // out-of-line helper + void initialize_misc(); void initialize(nmethod* nm, address begin, address limit); @@ -598,11 +591,15 @@ class RelocIterator : public StackObj { bool has_current() const { return _datalen >= 0; } void set_addr(address addr) { _addr = addr; } - bool addr_in_const() const { return addr() >= section_start(SECT_CONSTS); } + bool addr_in_const() const; address section_start(int n) const { - address res = _section_start[n]; - return (res != NULL) ? res : compute_section_start(n); + assert(_section_start[n], "must be initialized"); + return _section_start[n]; + } + address section_end(int n) const { + assert(_section_end[n], "must be initialized"); + return _section_end[n]; } // The address points to the affected displacement part of the instruction. diff --git a/hotspot/src/share/vm/code/scopeDesc.cpp b/hotspot/src/share/vm/code/scopeDesc.cpp index 2e1e19e6968..9eb1e888e38 100644 --- a/hotspot/src/share/vm/code/scopeDesc.cpp +++ b/hotspot/src/share/vm/code/scopeDesc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -174,7 +174,7 @@ void ScopeDesc::print_on(outputStream* st, PcDesc* pd) const { print_value_on(st); // decode offsets if (WizardMode) { - st->print("ScopeDesc[%d]@" PTR_FORMAT " ", _decode_offset, _code->instructions_begin()); + st->print("ScopeDesc[%d]@" PTR_FORMAT " ", _decode_offset, _code->content_begin()); st->print_cr(" offset: %d", _decode_offset); st->print_cr(" bci: %d", bci()); st->print_cr(" reexecute: %s", should_reexecute() ? "true" : "false"); diff --git a/hotspot/src/share/vm/code/stubs.cpp b/hotspot/src/share/vm/code/stubs.cpp index e8b49273152..7272f467334 100644 --- a/hotspot/src/share/vm/code/stubs.cpp +++ b/hotspot/src/share/vm/code/stubs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,9 +66,9 @@ StubQueue::StubQueue(StubInterface* stub_interface, int buffer_size, vm_exit_out_of_memory(size, err_msg("CodeCache: no room for %s", name)); } _stub_interface = stub_interface; - _buffer_size = blob->instructions_size(); - _buffer_limit = blob->instructions_size(); - _stub_buffer = blob->instructions_begin(); + _buffer_size = blob->content_size(); + _buffer_limit = blob->content_size(); + _stub_buffer = blob->content_begin(); _queue_begin = 0; _queue_end = 0; _number_of_stubs = 0; diff --git a/hotspot/src/share/vm/code/vtableStubs.cpp b/hotspot/src/share/vm/code/vtableStubs.cpp index 028cfe83850..e85a8732ff5 100644 --- a/hotspot/src/share/vm/code/vtableStubs.cpp +++ b/hotspot/src/share/vm/code/vtableStubs.cpp @@ -48,7 +48,7 @@ void* VtableStub::operator new(size_t size, int code_size) { if (blob == NULL) { vm_exit_out_of_memory(bytes, "CodeCache: no room for vtable chunks"); } - _chunk = blob->instructions_begin(); + _chunk = blob->content_begin(); _chunk_end = _chunk + bytes; Forte::register_stub("vtable stub", _chunk, _chunk_end); // Notify JVMTI about this stub. The event will be recorded by the enclosing diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 7288cac07ba..213ea0cc48c 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -123,20 +123,12 @@ int CompileBroker::_sum_standard_bytes_compiled = 0; int CompileBroker::_sum_nmethod_size = 0; int CompileBroker::_sum_nmethod_code_size = 0; -CompileQueue* CompileBroker::_method_queue = NULL; +CompileQueue* CompileBroker::_c2_method_queue = NULL; +CompileQueue* CompileBroker::_c1_method_queue = NULL; CompileTask* CompileBroker::_task_free_list = NULL; GrowableArray* CompileBroker::_method_threads = NULL; -// CompileTaskWrapper -// -// Assign this task to the current thread. Deallocate the task -// when the compilation is complete. -class CompileTaskWrapper : StackObj { -public: - CompileTaskWrapper(CompileTask* task); - ~CompileTaskWrapper(); -}; CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) { CompilerThread* thread = CompilerThread::current(); @@ -246,6 +238,12 @@ void CompileTask::print() { bool_to_str(_is_complete), bool_to_str(_is_success)); } + +void CompileTask::print_compilation(outputStream *st, methodOop method, char* method_name) { + nmethod::print_compilation(st, method_name,/*title*/ NULL, method, + is_blocking(), compile_id(), osr_bci(), comp_level()); +} + // ------------------------------------------------------------------ // CompileTask::print_line_on_error // @@ -258,32 +256,13 @@ void CompileTask::print() { // void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) { methodOop method = (methodOop)JNIHandles::resolve(_method); - // print compiler name st->print("%s:", CompileBroker::compiler(comp_level())->name()); - - // print compilation number - st->print("%3d", compile_id()); - - // print method attributes - const bool is_osr = osr_bci() != CompileBroker::standard_entry_bci; - { const char blocking_char = is_blocking() ? 'b' : ' '; - const char compile_type = is_osr ? '%' : ' '; - const char sync_char = method->is_synchronized() ? 's' : ' '; - const char exception_char = method->has_exception_handler() ? '!' : ' '; - const char tier_char = - is_highest_tier_compile(comp_level()) ? ' ' : ('0' + comp_level()); - st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, tier_char); + char* method_name = NULL; + if (method != NULL) { + method_name = method->name_and_sig_as_C_string(buf, buflen); } - - // Use buf to get method name and signature - if (method != NULL) st->print("%s", method->name_and_sig_as_C_string(buf, buflen)); - - // print osr_bci if any - if (is_osr) st->print(" @ %d", osr_bci()); - - // print method size - st->print_cr(" (%d bytes)", method->code_size()); + print_compilation(st, method, method_name); } // ------------------------------------------------------------------ @@ -298,29 +277,7 @@ void CompileTask::print_line() { // print compiler name if requested if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler(comp_level())->name()); - - // print compilation number - tty->print("%3d", compile_id()); - - // print method attributes - const bool is_osr = osr_bci() != CompileBroker::standard_entry_bci; - { const char blocking_char = is_blocking() ? 'b' : ' '; - const char compile_type = is_osr ? '%' : ' '; - const char sync_char = method->is_synchronized() ? 's' : ' '; - const char exception_char = method->has_exception_handler() ? '!' : ' '; - const char tier_char = - is_highest_tier_compile(comp_level()) ? ' ' : ('0' + comp_level()); - tty->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, tier_char); - } - - // print method name - method->print_short_name(tty); - - // print osr_bci if any - if (is_osr) tty->print(" @ %d", osr_bci()); - - // print method size - tty->print_cr(" (%d bytes)", method->code_size()); + print_compilation(tty, method(), NULL); } @@ -399,7 +356,7 @@ void CompileTask::log_task_done(CompileLog* log) { // nmethod* nm = code(); log->begin_elem("task_done success='%d' nmsize='%d' count='%d'", - _is_success, nm == NULL ? 0 : nm->instructions_size(), + _is_success, nm == NULL ? 0 : nm->content_size(), method->invocation_count()); int bec = method->backedge_count(); if (bec != 0) log->print(" backedge_count='%d'", bec); @@ -427,6 +384,7 @@ void CompileQueue::add(CompileTask* task) { assert(lock()->owned_by_self(), "must own lock"); task->set_next(NULL); + task->set_prev(NULL); if (_last == NULL) { // The compile queue is empty. @@ -437,8 +395,10 @@ void CompileQueue::add(CompileTask* task) { // Append the task to the queue. assert(_last->next() == NULL, "not last"); _last->set_next(task); + task->set_prev(_last); _last = task; } + ++_size; // Mark the method as being in the compile queue. ((methodOop)JNIHandles::resolve(task->method_handle()))->set_queued_for_compilation(); @@ -452,10 +412,9 @@ void CompileQueue::add(CompileTask* task) { } // Notify CompilerThreads that a task is available. - lock()->notify(); + lock()->notify_all(); } - // ------------------------------------------------------------------ // CompileQueue::get // @@ -464,7 +423,6 @@ CompileTask* CompileQueue::get() { NMethodSweeper::possibly_sweep(); MutexLocker locker(lock()); - // Wait for an available CompileTask. while (_first == NULL) { // There is no work to be done right now. Wait. @@ -481,19 +439,31 @@ CompileTask* CompileQueue::get() { lock()->wait(); } } - - CompileTask* task = _first; - - // Update queue first and last - _first =_first->next(); - if (_first == NULL) { - _last = NULL; - } - + CompileTask* task = CompilationPolicy::policy()->select_task(this); + remove(task); return task; - } +void CompileQueue::remove(CompileTask* task) +{ + assert(lock()->owned_by_self(), "must own lock"); + if (task->prev() != NULL) { + task->prev()->set_next(task->next()); + } else { + // max is the first element + assert(task == _first, "Sanity"); + _first = task->next(); + } + + if (task->next() != NULL) { + task->next()->set_prev(task->prev()); + } else { + // max is the last element + assert(task == _last, "Sanity"); + _last = task->prev(); + } + --_size; +} // ------------------------------------------------------------------ // CompileQueue::print @@ -545,7 +515,6 @@ CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) } } - // ------------------------------------------------------------------ // CompileBroker::compilation_init // @@ -554,18 +523,18 @@ void CompileBroker::compilation_init() { _last_method_compiled[0] = '\0'; // Set the interface to the current compiler(s). + int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple); + int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization); #ifdef COMPILER1 - _compilers[0] = new Compiler(); -#ifndef COMPILER2 - _compilers[1] = _compilers[0]; -#endif + if (c1_count > 0) { + _compilers[0] = new Compiler(); + } #endif // COMPILER1 #ifdef COMPILER2 - _compilers[1] = new C2Compiler(); -#ifndef COMPILER1 - _compilers[0] = _compilers[1]; -#endif + if (c2_count > 0) { + _compilers[1] = new C2Compiler(); + } #endif // COMPILER2 #ifdef SHARK @@ -580,9 +549,7 @@ void CompileBroker::compilation_init() { _task_free_list = NULL; // Start the CompilerThreads - init_compiler_threads(compiler_count()); - - + init_compiler_threads(c1_count, c2_count); // totalTime performance counter is always created as it is required // by the implementation of java.lang.management.CompilationMBean. { @@ -770,23 +737,38 @@ CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQue // CompileBroker::init_compiler_threads // // Initialize the compilation queue -void CompileBroker::init_compiler_threads(int compiler_count) { +void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler_count) { EXCEPTION_MARK; + assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?"); + if (c2_compiler_count > 0) { + _c2_method_queue = new CompileQueue("C2MethodQueue", MethodCompileQueue_lock); + } + if (c1_compiler_count > 0) { + _c1_method_queue = new CompileQueue("C1MethodQueue", MethodCompileQueue_lock); + } + + int compiler_count = c1_compiler_count + c2_compiler_count; - _method_queue = new CompileQueue("MethodQueue", MethodCompileQueue_lock); _method_threads = new (ResourceObj::C_HEAP) GrowableArray(compiler_count, true); char name_buffer[256]; - int i; - for (i = 0; i < compiler_count; i++) { + for (int i = 0; i < c2_compiler_count; i++) { // Create a name for our thread. - sprintf(name_buffer, "CompilerThread%d", i); + sprintf(name_buffer, "C2 CompilerThread%d", i); CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); - - CompilerThread* new_thread = make_compiler_thread(name_buffer, _method_queue, counters, CHECK); + CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, CHECK); _method_threads->append(new_thread); } + + for (int i = c2_compiler_count; i < compiler_count; i++) { + // Create a name for our thread. + sprintf(name_buffer, "C1 CompilerThread%d", i); + CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); + CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_method_queue, counters, CHECK); + _method_threads->append(new_thread); + } + if (UsePerfData) { PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, compiler_count, CHECK); @@ -796,7 +778,9 @@ void CompileBroker::init_compiler_threads(int compiler_count) { // ------------------------------------------------------------------ // CompileBroker::is_idle bool CompileBroker::is_idle() { - if (!_method_queue->is_empty()) { + if (_c2_method_queue != NULL && !_c2_method_queue->is_empty()) { + return false; + } else if (_c1_method_queue != NULL && !_c1_method_queue->is_empty()) { return false; } else { int num_threads = _method_threads->length(); @@ -859,6 +843,7 @@ void CompileBroker::compile_method_base(methodHandle method, return; } + // If this method is already in the compile queue, then // we do not block the current thread. if (compilation_is_in_queue(method, osr_bci)) { @@ -876,10 +861,11 @@ void CompileBroker::compile_method_base(methodHandle method, // Outputs from the following MutexLocker block: CompileTask* task = NULL; bool blocking = false; + CompileQueue* queue = compile_queue(comp_level); // Acquire our lock. { - MutexLocker locker(_method_queue->lock(), THREAD); + MutexLocker locker(queue->lock(), THREAD); // Make sure the method has not slipped into the queues since // last we checked; note that those checks were "fast bail-outs". @@ -945,7 +931,7 @@ void CompileBroker::compile_method_base(methodHandle method, // and in that case it's best to protect both the testing (here) of // these bits, and their updating (here and elsewhere) under a // common lock. - task = create_compile_task(_method_queue, + task = create_compile_task(queue, compile_id, method, osr_bci, comp_level, hot_method, hot_count, comment, @@ -959,6 +945,7 @@ void CompileBroker::compile_method_base(methodHandle method, nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, + int comp_level, methodHandle hot_method, int hot_count, const char* comment, TRAPS) { // make sure arguments make sense @@ -967,26 +954,9 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, assert(!method->is_abstract() && (osr_bci == InvocationEntryBci || !method->is_native()), "cannot compile abstract/native methods"); assert(!instanceKlass::cast(method->method_holder())->is_not_initialized(), "method holder must be initialized"); - int comp_level = CompilationPolicy::policy()->compilation_level(method, osr_bci); - -#ifdef TIERED - if (TieredCompilation && StressTieredRuntime) { - static int flipper = 0; - if (is_even(flipper++)) { - comp_level = CompLevel_fast_compile; - } else { - comp_level = CompLevel_full_optimization; - } + if (!TieredCompilation) { + comp_level = CompLevel_highest_tier; } -#ifdef SPARC - // QQQ FIX ME - // C2 only returns long results in G1 and c1 doesn't understand so disallow c2 - // compiles of long results - if (TieredCompilation && method()->result_type() == T_LONG) { - comp_level = CompLevel_fast_compile; - } -#endif // SPARC -#endif // TIERED // return quickly if possible @@ -1000,12 +970,10 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, if (osr_bci == InvocationEntryBci) { // standard compilation nmethod* method_code = method->code(); - if (method_code != NULL -#ifdef TIERED - && ( method_code->is_compiled_by_c2() || comp_level == CompLevel_fast_compile ) -#endif // TIERED - ) { - return method_code; + if (method_code != NULL) { + if (compilation_is_complete(method, osr_bci, comp_level)) { + return method_code; + } } if (method->is_not_compilable(comp_level)) return NULL; @@ -1021,10 +989,11 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, // osr compilation #ifndef TIERED // seems like an assert of dubious value - assert(comp_level == CompLevel_full_optimization, + assert(comp_level == CompLevel_highest_tier, "all OSR compiles are assumed to be at a single compilation lavel"); #endif // TIERED - nmethod* nm = method->lookup_osr_nmethod_for(osr_bci); + // We accept a higher level osr method + nmethod* nm = method->lookup_osr_nmethod_for(osr_bci, comp_level, false); if (nm != NULL) return nm; if (method->is_not_osr_compilable()) return NULL; } @@ -1071,8 +1040,7 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, // If the compiler is shut off due to code cache flushing or otherwise, // fail out now so blocking compiles dont hang the java thread if (!should_compile_new_jobs() || (UseCodeCacheFlushing && CodeCache::needs_flushing())) { - method->invocation_counter()->decay(); - method->backedge_counter()->decay(); + CompilationPolicy::policy()->delay_compilation(method()); return NULL; } @@ -1088,7 +1056,8 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, } // return requested nmethod - return osr_bci == InvocationEntryBci ? method->code() : method->lookup_osr_nmethod_for(osr_bci); + // We accept a higher level osr method + return osr_bci == InvocationEntryBci ? method->code() : method->lookup_osr_nmethod_for(osr_bci, comp_level, false); } @@ -1104,7 +1073,7 @@ bool CompileBroker::compilation_is_complete(methodHandle method, if (method->is_not_osr_compilable()) { return true; } else { - nmethod* result = method->lookup_osr_nmethod_for(osr_bci); + nmethod* result = method->lookup_osr_nmethod_for(osr_bci, comp_level, true); return (result != NULL); } } else { @@ -1113,15 +1082,7 @@ bool CompileBroker::compilation_is_complete(methodHandle method, } else { nmethod* result = method->code(); if (result == NULL) return false; -#ifdef TIERED - if (comp_level == CompLevel_fast_compile) { - // At worst the code is from c1 - return true; - } - // comp level must be full opt - return result->is_compiled_by_c2(); -#endif // TIERED - return true; + return comp_level == result->comp_level(); } } } @@ -1139,11 +1100,10 @@ bool CompileBroker::compilation_is_complete(methodHandle method, // versa). This can be remedied by a full queue search to disambiguate // cases. If it is deemed profitible, this may be done. bool CompileBroker::compilation_is_in_queue(methodHandle method, - int osr_bci) { + int osr_bci) { return method->queued_for_compilation(); } - // ------------------------------------------------------------------ // CompileBroker::compilation_is_prohibited // @@ -1151,11 +1111,9 @@ bool CompileBroker::compilation_is_in_queue(methodHandle method, bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level) { bool is_native = method->is_native(); // Some compilers may not support the compilation of natives. - // QQQ this needs some work ought to only record not compilable at - // the specified level if (is_native && (!CICompileNatives || !compiler(comp_level)->supports_native())) { - method->set_not_compilable_quietly(); + method->set_not_compilable_quietly(comp_level); return true; } @@ -1194,7 +1152,7 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, // compilations may be numbered separately from regular compilations // if certain debugging flags are used. uint CompileBroker::assign_compile_id(methodHandle method, int osr_bci) { - assert(_method_queue->lock()->owner() == JavaThread::current(), + assert(MethodCompileQueue_lock->owner() == Thread::current(), "must hold the compilation queue lock"); bool is_osr = (osr_bci != standard_entry_bci); assert(!method->is_native(), "no longer compile natives"); @@ -1643,7 +1601,6 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { #endif } - // ------------------------------------------------------------------ // CompileBroker::handle_full_code_cache // @@ -1652,12 +1609,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { void CompileBroker::handle_full_code_cache() { UseInterpreter = true; if (UseCompiler || AlwaysCompileLoopMethods ) { - CompilerThread* thread = CompilerThread::current(); - CompileLog* log = thread->log(); - if (log != NULL) { - log->begin_elem("code_cache_full"); - log->stamp(); - log->end_elem(); + if (xtty != NULL) { + xtty->begin_elem("code_cache_full"); + xtty->stamp(); + xtty->end_elem(); } warning("CodeCache is full. Compiler has been disabled."); warning("Try increasing the code cache size using -XX:ReservedCodeCacheSize="); @@ -1849,13 +1804,13 @@ void CompileBroker::collect_statistics(CompilerThread* thread, elapsedTimer time } // Collect counts of successful compilations - _sum_nmethod_size += code->total_size(); - _sum_nmethod_code_size += code->code_size(); + _sum_nmethod_size += code->total_size(); + _sum_nmethod_code_size += code->insts_size(); _total_compile_count++; if (UsePerfData) { - _perf_sum_nmethod_size->inc(code->total_size()); - _perf_sum_nmethod_code_size->inc(code->code_size()); + _perf_sum_nmethod_size->inc( code->total_size()); + _perf_sum_nmethod_code_size->inc(code->insts_size()); _perf_total_compile_count->inc(); } @@ -1885,12 +1840,12 @@ void CompileBroker::print_times() { CompileBroker::_t_standard_compilation.seconds() / CompileBroker::_total_standard_compile_count); tty->print_cr(" On stack replacement : %6.3f s, Average : %2.3f", CompileBroker::_t_osr_compilation.seconds(), CompileBroker::_t_osr_compilation.seconds() / CompileBroker::_total_osr_compile_count); - if (compiler(CompLevel_fast_compile)) { - compiler(CompLevel_fast_compile)->print_timers(); - if (compiler(CompLevel_fast_compile) != compiler(CompLevel_highest_tier)) - compiler(CompLevel_highest_tier)->print_timers(); + if (compiler(CompLevel_simple) != NULL) { + compiler(CompLevel_simple)->print_timers(); + } + if (compiler(CompLevel_full_optimization) != NULL) { + compiler(CompLevel_full_optimization)->print_timers(); } - tty->cr(); int tcb = CompileBroker::_sum_osr_bytes_compiled + CompileBroker::_sum_standard_bytes_compiled; tty->print_cr(" Total compiled bytecodes : %6d bytes", tcb); diff --git a/hotspot/src/share/vm/compiler/compileBroker.hpp b/hotspot/src/share/vm/compiler/compileBroker.hpp index dfb031e24d8..e0845fb89b0 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.hpp +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ class CompileTask : public CHeapObj { int _comp_level; int _num_inlined_bytecodes; nmethodLocker* _code_handle; // holder of eventual result - CompileTask* _next; + CompileTask* _next, *_prev; // Fields used for logging why the compilation was initiated: jlong _time_queued; // in units of os::elapsed_counter() @@ -49,6 +49,7 @@ class CompileTask : public CHeapObj { int _hot_count; // information about its invocation counter const char* _comment; // more info about the task + void print_compilation(outputStream *st, methodOop method, char* method_name); public: CompileTask() { _lock = new Monitor(Mutex::nonleaf+2, "CompileTaskLock"); @@ -85,15 +86,17 @@ class CompileTask : public CHeapObj { CompileTask* next() const { return _next; } void set_next(CompileTask* next) { _next = next; } + CompileTask* prev() const { return _prev; } + void set_prev(CompileTask* prev) { _prev = prev; } void print(); void print_line(); + void print_line_on_error(outputStream* st, char* buf, int buflen); void log_task(xmlStream* log); void log_task_queued(); void log_task_start(CompileLog* log); void log_task_done(CompileLog* log); - }; // CompilerCounters @@ -141,7 +144,6 @@ class CompilerCounters : public CHeapObj { PerfCounter* compile_counter() { return _perf_compiles; } }; - // CompileQueue // // A list of CompileTasks. @@ -153,26 +155,42 @@ class CompileQueue : public CHeapObj { CompileTask* _first; CompileTask* _last; + int _size; public: CompileQueue(const char* name, Monitor* lock) { _name = name; _lock = lock; _first = NULL; _last = NULL; + _size = 0; } const char* name() const { return _name; } Monitor* lock() const { return _lock; } void add(CompileTask* task); + void remove(CompileTask* task); + CompileTask* first() { return _first; } + CompileTask* last() { return _last; } CompileTask* get(); bool is_empty() const { return _first == NULL; } + int size() const { return _size; } void print(); }; +// CompileTaskWrapper +// +// Assign this task to the current thread. Deallocate the task +// when the compilation is complete. +class CompileTaskWrapper : StackObj { +public: + CompileTaskWrapper(CompileTask* task); + ~CompileTaskWrapper(); +}; + // Compilation // @@ -208,7 +226,8 @@ class CompileBroker: AllStatic { static int _last_compile_level; static char _last_method_compiled[name_buffer_length]; - static CompileQueue* _method_queue; + static CompileQueue* _c2_method_queue; + static CompileQueue* _c1_method_queue; static CompileTask* _task_free_list; static GrowableArray* _method_threads; @@ -256,19 +275,9 @@ class CompileBroker: AllStatic { static int _sum_nmethod_size; static int _sum_nmethod_code_size; - static int compiler_count() { - return CICompilerCountPerCPU - // Example: if CICompilerCountPerCPU is true, then we get - // max(log2(8)-1,1) = 2 compiler threads on an 8-way machine. - // May help big-app startup time. - ? (MAX2(log2_intptr(os::active_processor_count())-1,1)) - : CICompilerCount; - } - static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, TRAPS); - static void init_compiler_threads(int compiler_count); + static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count); static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level); - static bool compilation_is_in_queue (methodHandle method, int osr_bci); static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level); static uint assign_compile_id (methodHandle method, int osr_bci); static bool is_compile_blocking (methodHandle method, int osr_bci); @@ -301,23 +310,35 @@ class CompileBroker: AllStatic { int hot_count, const char* comment, TRAPS); - + static CompileQueue* compile_queue(int comp_level) { + if (is_c2_compile(comp_level)) return _c2_method_queue; + if (is_c1_compile(comp_level)) return _c1_method_queue; + return NULL; + } public: enum { // The entry bci used for non-OSR compilations. standard_entry_bci = InvocationEntryBci }; - static AbstractCompiler* compiler(int level ) { - if (level == CompLevel_fast_compile) return _compilers[0]; - assert(level == CompLevel_highest_tier, "what level?"); - return _compilers[1]; + static AbstractCompiler* compiler(int comp_level) { + if (is_c2_compile(comp_level)) return _compilers[1]; // C2 + if (is_c1_compile(comp_level)) return _compilers[0]; // C1 + return NULL; } + static bool compilation_is_in_queue(methodHandle method, int osr_bci); + static int queue_size(int comp_level) { + CompileQueue *q = compile_queue(comp_level); + return q != NULL ? q->size() : 0; + } static void compilation_init(); static void init_compiler_thread_log(); - static nmethod* compile_method(methodHandle method, int osr_bci, - methodHandle hot_method, int hot_count, + static nmethod* compile_method(methodHandle method, + int osr_bci, + int comp_level, + methodHandle hot_method, + int hot_count, const char* comment, TRAPS); static void compiler_thread_loop(); diff --git a/hotspot/src/share/vm/compiler/disassembler.cpp b/hotspot/src/share/vm/compiler/disassembler.cpp index 8176a816463..175d874da8c 100644 --- a/hotspot/src/share/vm/compiler/disassembler.cpp +++ b/hotspot/src/share/vm/compiler/disassembler.cpp @@ -407,7 +407,7 @@ void Disassembler::decode(CodeBlob* cb, outputStream* st) { if (!load_library()) return; decode_env env(cb, st); env.output()->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb); - env.decode_instructions(cb->instructions_begin(), cb->instructions_end()); + env.decode_instructions(cb->code_begin(), cb->code_end()); } @@ -424,12 +424,12 @@ void Disassembler::decode(nmethod* nm, outputStream* st) { env.output()->print_cr("Code:"); #ifdef SHARK - SharkEntry* entry = (SharkEntry *) nm->instructions_begin(); - unsigned char* p = entry->code_start(); + SharkEntry* entry = (SharkEntry *) nm->code_begin(); + unsigned char* p = entry->code_start(); unsigned char* end = entry->code_limit(); #else - unsigned char* p = nm->instructions_begin(); - unsigned char* end = nm->instructions_end(); + unsigned char* p = nm->code_begin(); + unsigned char* end = nm->code_end(); #endif // SHARK // If there has been profiling, print the buckets. diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp index aac936ca2ed..5455523a96e 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp @@ -256,7 +256,7 @@ TreeChunk* TreeList::head_as_TreeChunk() { } TreeChunk* TreeList::first_available() { - guarantee(head() != NULL, "The head of the list cannot be NULL"); + assert(head() != NULL, "The head of the list cannot be NULL"); FreeChunk* fc = head()->next(); TreeChunk* retTC; if (fc == NULL) { @@ -272,7 +272,7 @@ TreeChunk* TreeList::first_available() { // those in the list for this size; potentially slow and expensive, // use with caution! TreeChunk* TreeList::largest_address() { - guarantee(head() != NULL, "The head of the list cannot be NULL"); + assert(head() != NULL, "The head of the list cannot be NULL"); FreeChunk* fc = head()->next(); TreeChunk* retTC; if (fc == NULL) { diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index 28f6ef4b0a3..7c1d13de3f8 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -402,6 +402,29 @@ size_t CompactibleFreeListSpace::max_alloc_in_words() const { return res; } +void LinearAllocBlock::print_on(outputStream* st) const { + st->print_cr(" LinearAllocBlock: ptr = " PTR_FORMAT ", word_size = " SIZE_FORMAT + ", refillsize = " SIZE_FORMAT ", allocation_size_limit = " SIZE_FORMAT, + _ptr, _word_size, _refillSize, _allocation_size_limit); +} + +void CompactibleFreeListSpace::print_on(outputStream* st) const { + st->print_cr("COMPACTIBLE FREELIST SPACE"); + st->print_cr(" Space:"); + Space::print_on(st); + + st->print_cr("promoInfo:"); + _promoInfo.print_on(st); + + st->print_cr("_smallLinearAllocBlock"); + _smallLinearAllocBlock.print_on(st); + + // dump_memory_block(_smallLinearAllocBlock->_ptr, 128); + + st->print_cr(" _fitStrategy = %s, _adaptive_freelists = %s", + _fitStrategy?"true":"false", _adaptive_freelists?"true":"false"); +} + void CompactibleFreeListSpace::print_indexed_free_lists(outputStream* st) const { reportIndexedFreeListStatistics(); @@ -557,13 +580,15 @@ size_t CompactibleFreeListSpace::maxChunkSizeInIndexedFreeLists() const { void CompactibleFreeListSpace::set_end(HeapWord* value) { HeapWord* prevEnd = end(); assert(prevEnd != value, "unnecessary set_end call"); - assert(prevEnd == NULL || value >= unallocated_block(), "New end is below unallocated block"); + assert(prevEnd == NULL || !BlockOffsetArrayUseUnallocatedBlock || value >= unallocated_block(), + "New end is below unallocated block"); _end = value; if (prevEnd != NULL) { // Resize the underlying block offset table. _bt.resize(pointer_delta(value, bottom())); if (value <= prevEnd) { - assert(value >= unallocated_block(), "New end is below unallocated block"); + assert(!BlockOffsetArrayUseUnallocatedBlock || value >= unallocated_block(), + "New end is below unallocated block"); } else { // Now, take this new chunk and add it to the free blocks. // Note that the BOT has not yet been updated for this block. @@ -938,7 +963,6 @@ HeapWord* CompactibleFreeListSpace::block_start_careful(const void* p) const { size_t CompactibleFreeListSpace::block_size(const HeapWord* p) const { NOT_PRODUCT(verify_objects_initialized()); - assert(MemRegion(bottom(), end()).contains(p), "p not in space"); // This must be volatile, or else there is a danger that the compiler // will compile the code below into a sometimes-infinite loop, by keeping // the value read the first time in a register. @@ -957,7 +981,7 @@ size_t CompactibleFreeListSpace::block_size(const HeapWord* p) const { // must read from what 'p' points to in each loop. klassOop k = ((volatile oopDesc*)p)->klass_or_null(); if (k != NULL) { - assert(k->is_oop(true /* ignore mark word */), "Should really be klass oop."); + assert(k->is_oop(true /* ignore mark word */), "Should be klass oop"); oop o = (oop)p; assert(o->is_parsable(), "Should be parsable"); assert(o->is_oop(true /* ignore mark word */), "Should be an oop."); @@ -1231,7 +1255,6 @@ HeapWord* CompactibleFreeListSpace::allocate_adaptive_freelists(size_t size) { // satisfy the request. This is different that // evm. // Don't record chunk off a LinAB? smallSplitBirth(size); - } else { // Raid the exact free lists larger than size, even if they are not // overpopulated. @@ -1449,6 +1472,7 @@ CompactibleFreeListSpace::getChunkFromLinearAllocBlock(LinearAllocBlock *blk, // Update BOT last so that other (parallel) GC threads see a consistent // view of the BOT and free blocks. // Above must occur before BOT is updated below. + OrderAccess::storestore(); _bt.split_block(res, blk_size, size); // adjust block offset table } return res; @@ -1477,6 +1501,7 @@ HeapWord* CompactibleFreeListSpace::getChunkFromLinearAllocBlockRemainder( // Update BOT last so that other (parallel) GC threads see a consistent // view of the BOT and free blocks. // Above must occur before BOT is updated below. + OrderAccess::storestore(); _bt.split_block(res, blk_size, size); // adjust block offset table _bt.allocated(res, size); } @@ -1856,6 +1881,8 @@ CompactibleFreeListSpace::splitChunkAndReturnRemainder(FreeChunk* chunk, ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads. // Above must occur before BOT is updated below. // adjust block offset table + OrderAccess::storestore(); + assert(chunk->isFree() && ffc->isFree(), "Error"); _bt.split_block((HeapWord*)chunk, chunk->size(), new_size); if (rem_size < SmallForDictionary) { bool is_par = (SharedHeap::heap()->n_par_threads() > 0); @@ -1911,8 +1938,7 @@ void CompactibleFreeListSpace::save_marks() { // mark the "end" of the used space at the time of this call; // note, however, that promoted objects from this point // on are tracked in the _promoInfo below. - set_saved_mark_word(BlockOffsetArrayUseUnallocatedBlock ? - unallocated_block() : end()); + set_saved_mark_word(unallocated_block()); // inform allocator that promotions should be tracked. assert(_promoInfo.noPromotions(), "_promoInfo inconsistency"); _promoInfo.startTrackingPromotions(); @@ -1920,8 +1946,8 @@ void CompactibleFreeListSpace::save_marks() { bool CompactibleFreeListSpace::no_allocs_since_save_marks() { assert(_promoInfo.tracking(), "No preceding save_marks?"); - guarantee(SharedHeap::heap()->n_par_threads() == 0, - "Shouldn't be called (yet) during parallel part of gc."); + assert(SharedHeap::heap()->n_par_threads() == 0, + "Shouldn't be called if using parallel gc."); return _promoInfo.noPromotions(); } @@ -2238,8 +2264,7 @@ void CompactibleFreeListSpace::split(size_t from, size_t to1) { } void CompactibleFreeListSpace::print() const { - tty->print(" CompactibleFreeListSpace"); - Space::print(); + Space::print_on(tty); } void CompactibleFreeListSpace::prepare_for_verify() { @@ -2253,18 +2278,28 @@ class VerifyAllBlksClosure: public BlkClosure { private: const CompactibleFreeListSpace* _sp; const MemRegion _span; + HeapWord* _last_addr; + size_t _last_size; + bool _last_was_obj; + bool _last_was_live; public: VerifyAllBlksClosure(const CompactibleFreeListSpace* sp, - MemRegion span) : _sp(sp), _span(span) { } + MemRegion span) : _sp(sp), _span(span), + _last_addr(NULL), _last_size(0), + _last_was_obj(false), _last_was_live(false) { } virtual size_t do_blk(HeapWord* addr) { size_t res; + bool was_obj = false; + bool was_live = false; if (_sp->block_is_obj(addr)) { + was_obj = true; oop p = oop(addr); guarantee(p->is_oop(), "Should be an oop"); res = _sp->adjustObjectSize(p->size()); if (_sp->obj_is_alive(addr)) { + was_live = true; p->verify(); } } else { @@ -2275,7 +2310,20 @@ class VerifyAllBlksClosure: public BlkClosure { "Chunk should be on a free list"); } } - guarantee(res != 0, "Livelock: no rank reduction!"); + if (res == 0) { + gclog_or_tty->print_cr("Livelock: no rank reduction!"); + gclog_or_tty->print_cr( + " Current: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n" + " Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n", + addr, res, was_obj ?"true":"false", was_live ?"true":"false", + _last_addr, _last_size, _last_was_obj?"true":"false", _last_was_live?"true":"false"); + _sp->print_on(gclog_or_tty); + guarantee(false, "Seppuku!"); + } + _last_addr = addr; + _last_size = res; + _last_was_obj = was_obj; + _last_was_live = was_live; return res; } }; @@ -2521,7 +2569,7 @@ void CFLS_LAB::modify_initialization(size_t n, unsigned wt) { HeapWord* CFLS_LAB::alloc(size_t word_sz) { FreeChunk* res; - word_sz = _cfls->adjustObjectSize(word_sz); + assert(word_sz == _cfls->adjustObjectSize(word_sz), "Error"); if (word_sz >= CompactibleFreeListSpace::IndexSetSize) { // This locking manages sync with other large object allocations. MutexLockerEx x(_cfls->parDictionaryAllocLock(), @@ -2667,12 +2715,12 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n (cur_sz < CompactibleFreeListSpace::IndexSetSize) && (CMSSplitIndexedFreeListBlocks || k <= 1); k++, cur_sz = k * word_sz) { - FreeList* gfl = &_indexedFreeList[cur_sz]; FreeList fl_for_cur_sz; // Empty. fl_for_cur_sz.set_size(cur_sz); { MutexLockerEx x(_indexedFreeListParLocks[cur_sz], Mutex::_no_safepoint_check_flag); + FreeList* gfl = &_indexedFreeList[cur_sz]; if (gfl->count() != 0) { // nn is the number of chunks of size cur_sz that // we'd need to split k-ways each, in order to create @@ -2685,9 +2733,9 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n // we increment the split death count by the number of blocks // we just took from the cur_sz-size blocks list and which // we will be splitting below. - ssize_t deaths = _indexedFreeList[cur_sz].splitDeaths() + + ssize_t deaths = gfl->splitDeaths() + fl_for_cur_sz.count(); - _indexedFreeList[cur_sz].set_splitDeaths(deaths); + gfl->set_splitDeaths(deaths); } } } @@ -2703,18 +2751,25 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n // access the main chunk sees it as a single free block until we // change it. size_t fc_size = fc->size(); + assert(fc->isFree(), "Error"); for (int i = k-1; i >= 0; i--) { FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz); + assert((i != 0) || + ((fc == ffc) && ffc->isFree() && + (ffc->size() == k*word_sz) && (fc_size == word_sz)), + "Counting error"); ffc->setSize(word_sz); - ffc->linkNext(NULL); ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads. + ffc->linkNext(NULL); // Above must occur before BOT is updated below. - // splitting from the right, fc_size == (k - i + 1) * wordsize - _bt.mark_block((HeapWord*)ffc, word_sz); + OrderAccess::storestore(); + // splitting from the right, fc_size == i * word_sz + _bt.mark_block((HeapWord*)ffc, word_sz, true /* reducing */); fc_size -= word_sz; - _bt.verify_not_unallocated((HeapWord*)ffc, ffc->size()); + assert(fc_size == i*word_sz, "Error"); + _bt.verify_not_unallocated((HeapWord*)ffc, word_sz); _bt.verify_single_block((HeapWord*)fc, fc_size); - _bt.verify_single_block((HeapWord*)ffc, ffc->size()); + _bt.verify_single_block((HeapWord*)ffc, word_sz); // Push this on "fl". fl->returnChunkAtHead(ffc); } @@ -2744,7 +2799,7 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n _dictionary->minSize()), FreeBlockDictionary::atLeast); if (fc != NULL) { - _bt.allocated((HeapWord*)fc, fc->size()); // update _unallocated_blk + _bt.allocated((HeapWord*)fc, fc->size(), true /* reducing */); // update _unallocated_blk dictionary()->dictCensusUpdate(fc->size(), true /*split*/, false /*birth*/); @@ -2754,8 +2809,10 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n } } if (fc == NULL) return; - assert((ssize_t)n >= 1, "Control point invariant"); // Otherwise, split up that block. + assert((ssize_t)n >= 1, "Control point invariant"); + assert(fc->isFree(), "Error: should be a free block"); + _bt.verify_single_block((HeapWord*)fc, fc->size()); const size_t nn = fc->size() / word_sz; n = MIN2(nn, n); assert((ssize_t)n >= 1, "Control point invariant"); @@ -2773,6 +2830,7 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n // dictionary and return, leaving "fl" empty. if (n == 0) { returnChunkToDictionary(fc); + assert(fl->count() == 0, "We never allocated any blocks"); return; } @@ -2785,11 +2843,14 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n size_t prefix_size = n * word_sz; rem_fc = (FreeChunk*)((HeapWord*)fc + prefix_size); rem_fc->setSize(rem); - rem_fc->linkNext(NULL); rem_fc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads. + rem_fc->linkNext(NULL); // Above must occur before BOT is updated below. assert((ssize_t)n > 0 && prefix_size > 0 && rem_fc > fc, "Error"); + OrderAccess::storestore(); _bt.split_block((HeapWord*)fc, fc->size(), prefix_size); + assert(fc->isFree(), "Error"); + fc->setSize(prefix_size); if (rem >= IndexSetSize) { returnChunkToDictionary(rem_fc); dictionary()->dictCensusUpdate(rem, true /*split*/, true /*birth*/); @@ -2815,11 +2876,12 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n for (ssize_t i = n-1; i > 0; i--) { FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz); ffc->setSize(word_sz); - ffc->linkNext(NULL); ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads. + ffc->linkNext(NULL); // Above must occur before BOT is updated below. + OrderAccess::storestore(); // splitting from the right, fc_size == (n - i + 1) * wordsize - _bt.mark_block((HeapWord*)ffc, word_sz); + _bt.mark_block((HeapWord*)ffc, word_sz, true /* reducing */); fc_size -= word_sz; _bt.verify_not_unallocated((HeapWord*)ffc, ffc->size()); _bt.verify_single_block((HeapWord*)ffc, ffc->size()); @@ -2828,9 +2890,11 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n fl->returnChunkAtHead(ffc); } // First chunk + assert(fc->isFree() && fc->size() == n*word_sz, "Error: should still be a free block"); + // The blocks above should show their new sizes before the first block below fc->setSize(word_sz); + fc->linkPrev(NULL); // idempotent wrt free-ness, see assert above fc->linkNext(NULL); - fc->linkPrev(NULL); _bt.verify_not_unallocated((HeapWord*)fc, fc->size()); _bt.verify_single_block((HeapWord*)fc, fc->size()); fl->returnChunkAtHead(fc); diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index 8bca5df52f5..6d67e941161 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,8 @@ class LinearAllocBlock VALUE_OBJ_CLASS_SPEC { size_t _word_size; size_t _refillSize; size_t _allocation_size_limit; // largest size that will be allocated + + void print_on(outputStream* st) const; }; // Concrete subclass of CompactibleSpace that implements @@ -249,10 +251,14 @@ class CompactibleFreeListSpace: public CompactibleSpace { size_t numFreeBlocksInIndexedFreeLists() const; // Accessor HeapWord* unallocated_block() const { - HeapWord* ub = _bt.unallocated_block(); - assert(ub >= bottom() && - ub <= end(), "space invariant"); - return ub; + if (BlockOffsetArrayUseUnallocatedBlock) { + HeapWord* ub = _bt.unallocated_block(); + assert(ub >= bottom() && + ub <= end(), "space invariant"); + return ub; + } else { + return end(); + } } void freed(HeapWord* start, size_t size) { _bt.freed(start, size); @@ -476,6 +482,7 @@ class CompactibleFreeListSpace: public CompactibleSpace { // Debugging support void print() const; + void print_on(outputStream* st) const; void prepare_for_verify(); void verify(bool allow_dirty) const; void verifyFreeLists() const PRODUCT_RETURN; diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 1fac91a5466..aab22dacf17 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -1019,7 +1019,7 @@ HeapWord* ConcurrentMarkSweepGeneration::allocate(size_t size, } HeapWord* ConcurrentMarkSweepGeneration::have_lock_and_allocate(size_t size, - bool tlab) { + bool tlab /* ignored */) { assert_lock_strong(freelistLock()); size_t adjustedSize = CompactibleFreeListSpace::adjustObjectSize(size); HeapWord* res = cmsSpace()->allocate(adjustedSize); @@ -1032,6 +1032,11 @@ HeapWord* ConcurrentMarkSweepGeneration::have_lock_and_allocate(size_t size, // allowing the object to be blackened (and its references scanned) // either during a preclean phase or at the final checkpoint. if (res != NULL) { + // We may block here with an uninitialized object with + // its mark-bit or P-bits not yet set. Such objects need + // to be safely navigable by block_start(). + assert(oop(res)->klass_or_null() == NULL, "Object should be uninitialized here."); + assert(!((FreeChunk*)res)->isFree(), "Error, block will look free but show wrong size"); collector()->direct_allocated(res, adjustedSize); _direct_allocated_words += adjustedSize; // allocation counters @@ -1061,8 +1066,14 @@ void CMSCollector::direct_allocated(HeapWord* start, size_t size) { // [see comments preceding SweepClosure::do_blk() below for details] // 1. need to mark the object as live so it isn't collected // 2. need to mark the 2nd bit to indicate the object may be uninitialized - // 3. need to mark the end of the object so sweeper can skip over it - // if it's uninitialized when the sweeper reaches it. + // 3. need to mark the end of the object so marking, precleaning or sweeping + // can skip over uninitialized or unparsable objects. An allocated + // object is considered uninitialized for our purposes as long as + // its klass word is NULL. (Unparsable objects are those which are + // initialized in the sense just described, but whose sizes can still + // not be correctly determined. Note that the class of unparsable objects + // can only occur in the perm gen. All old gen objects are parsable + // as soon as they are initialized.) _markBitMap.mark(start); // object is live _markBitMap.mark(start + 1); // object is potentially uninitialized? _markBitMap.mark(start + size - 1); @@ -1088,7 +1099,13 @@ void CMSCollector::promoted(bool par, HeapWord* start, // We don't need to mark the object as uninitialized (as // in direct_allocated above) because this is being done with the // world stopped and the object will be initialized by the - // time the sweeper gets to look at it. + // time the marking, precleaning or sweeping get to look at it. + // But see the code for copying objects into the CMS generation, + // where we need to ensure that concurrent readers of the + // block offset table are able to safely navigate a block that + // is in flux from being free to being allocated (and in + // transition while being copied into) and subsequently + // becoming a bona-fide object when the copy/promotion is complete. assert(SafepointSynchronize::is_at_safepoint(), "expect promotion only at safepoints"); @@ -1304,6 +1321,48 @@ ConcurrentMarkSweepGeneration::allocation_limit_reached(Space* space, return collector()->allocation_limit_reached(space, top, word_sz); } +// IMPORTANT: Notes on object size recognition in CMS. +// --------------------------------------------------- +// A block of storage in the CMS generation is always in +// one of three states. A free block (FREE), an allocated +// object (OBJECT) whose size() method reports the correct size, +// and an intermediate state (TRANSIENT) in which its size cannot +// be accurately determined. +// STATE IDENTIFICATION: (32 bit and 64 bit w/o COOPS) +// ----------------------------------------------------- +// FREE: klass_word & 1 == 1; mark_word holds block size +// +// OBJECT: klass_word installed; klass_word != 0 && klass_word & 1 == 0; +// obj->size() computes correct size +// [Perm Gen objects needs to be "parsable" before they can be navigated] +// +// TRANSIENT: klass_word == 0; size is indeterminate until we become an OBJECT +// +// STATE IDENTIFICATION: (64 bit+COOPS) +// ------------------------------------ +// FREE: mark_word & CMS_FREE_BIT == 1; mark_word & ~CMS_FREE_BIT gives block_size +// +// OBJECT: klass_word installed; klass_word != 0; +// obj->size() computes correct size +// [Perm Gen comment above continues to hold] +// +// TRANSIENT: klass_word == 0; size is indeterminate until we become an OBJECT +// +// +// STATE TRANSITION DIAGRAM +// +// mut / parnew mut / parnew +// FREE --------------------> TRANSIENT ---------------------> OBJECT --| +// ^ | +// |------------------------ DEAD <------------------------------------| +// sweep mut +// +// While a block is in TRANSIENT state its size cannot be determined +// so readers will either need to come back later or stall until +// the size can be determined. Note that for the case of direct +// allocation, P-bits, when available, may be used to determine the +// size of an object that may not yet have been initialized. + // Things to support parallel young-gen collection. oop ConcurrentMarkSweepGeneration::par_promote(int thread_num, @@ -1331,33 +1390,39 @@ ConcurrentMarkSweepGeneration::par_promote(int thread_num, } } assert(promoInfo->has_spooling_space(), "Control point invariant"); - HeapWord* obj_ptr = ps->lab.alloc(word_sz); + const size_t alloc_sz = CompactibleFreeListSpace::adjustObjectSize(word_sz); + HeapWord* obj_ptr = ps->lab.alloc(alloc_sz); if (obj_ptr == NULL) { - obj_ptr = expand_and_par_lab_allocate(ps, word_sz); + obj_ptr = expand_and_par_lab_allocate(ps, alloc_sz); if (obj_ptr == NULL) { return NULL; } } oop obj = oop(obj_ptr); + OrderAccess::storestore(); assert(obj->klass_or_null() == NULL, "Object should be uninitialized here."); + assert(!((FreeChunk*)obj_ptr)->isFree(), "Error, block will look free but show wrong size"); + // IMPORTANT: See note on object initialization for CMS above. // Otherwise, copy the object. Here we must be careful to insert the // klass pointer last, since this marks the block as an allocated object. // Except with compressed oops it's the mark word. HeapWord* old_ptr = (HeapWord*)old; + // Restore the mark word copied above. + obj->set_mark(m); + assert(obj->klass_or_null() == NULL, "Object should be uninitialized here."); + assert(!((FreeChunk*)obj_ptr)->isFree(), "Error, block will look free but show wrong size"); + OrderAccess::storestore(); + + if (UseCompressedOops) { + // Copy gap missed by (aligned) header size calculation below + obj->set_klass_gap(old->klass_gap()); + } if (word_sz > (size_t)oopDesc::header_size()) { Copy::aligned_disjoint_words(old_ptr + oopDesc::header_size(), obj_ptr + oopDesc::header_size(), word_sz - oopDesc::header_size()); } - if (UseCompressedOops) { - // Copy gap missed by (aligned) header size calculation above - obj->set_klass_gap(old->klass_gap()); - } - - // Restore the mark word copied above. - obj->set_mark(m); - // Now we can track the promoted object, if necessary. We take care // to delay the transition from uninitialized to full object // (i.e., insertion of klass pointer) until after, so that it @@ -1365,18 +1430,22 @@ ConcurrentMarkSweepGeneration::par_promote(int thread_num, if (promoInfo->tracking()) { promoInfo->track((PromotedObject*)obj, old->klass()); } + assert(obj->klass_or_null() == NULL, "Object should be uninitialized here."); + assert(!((FreeChunk*)obj_ptr)->isFree(), "Error, block will look free but show wrong size"); + assert(old->is_oop(), "Will use and dereference old klass ptr below"); // Finally, install the klass pointer (this should be volatile). + OrderAccess::storestore(); obj->set_klass(old->klass()); + // We should now be able to calculate the right size for this object + assert(obj->is_oop() && obj->size() == (int)word_sz, "Error, incorrect size computed for promoted object"); - assert(old->is_oop(), "Will dereference klass ptr below"); collector()->promoted(true, // parallel obj_ptr, old->is_objArray(), word_sz); NOT_PRODUCT( - Atomic::inc(&_numObjectsPromoted); - Atomic::add((jint)CompactibleFreeListSpace::adjustObjectSize(obj->size()), - &_numWordsPromoted); + Atomic::inc_ptr(&_numObjectsPromoted); + Atomic::add_ptr(alloc_sz, &_numWordsPromoted); ) return obj; @@ -1965,6 +2034,9 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { _intra_sweep_estimate.padded_average()); } + { + TraceCMSMemoryManagerStats(); + } GenMarkSweep::invoke_at_safepoint(_cmsGen->level(), ref_processor(), clear_all_soft_refs); #ifdef ASSERT @@ -3415,6 +3487,7 @@ CMSPhaseAccounting::~CMSPhaseAccounting() { void CMSCollector::checkpointRootsInitial(bool asynch) { assert(_collectorState == InitialMarking, "Wrong collector state"); check_correct_thread_executing(); + TraceCMSMemoryManagerStats tms(_collectorState); ReferenceProcessor* rp = ref_processor(); SpecializationStats::clear(); assert(_restart_addr == NULL, "Control point invariant"); @@ -4748,6 +4821,7 @@ void CMSCollector::checkpointRootsFinal(bool asynch, // world is stopped at this checkpoint assert(SafepointSynchronize::is_at_safepoint(), "world should be stopped"); + TraceCMSMemoryManagerStats tms(_collectorState); verify_work_stacks_empty(); verify_overflow_empty(); @@ -5849,6 +5923,8 @@ void CMSCollector::sweep(bool asynch) { verify_work_stacks_empty(); verify_overflow_empty(); increment_sweep_count(); + TraceCMSMemoryManagerStats tms(_collectorState); + _inter_sweep_timer.stop(); _inter_sweep_estimate.sample(_inter_sweep_timer.seconds()); size_policy()->avg_cms_free_at_sweep()->sample(_cmsGen->free()); @@ -7861,14 +7937,20 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { FreeChunk* fc = (FreeChunk*)addr; size_t res; - // check if we are done sweepinrg - if (addr == _limit) { // we have swept up to the limit, do nothing more + // Check if we are done sweeping. Below we check "addr >= _limit" rather + // than "addr == _limit" because although _limit was a block boundary when + // we started the sweep, it may no longer be one because heap expansion + // may have caused us to coalesce the block ending at the address _limit + // with a newly expanded chunk (this happens when _limit was set to the + // previous _end of the space), so we may have stepped past _limit; see CR 6977970. + if (addr >= _limit) { // we have swept up to or past the limit, do nothing more assert(_limit >= _sp->bottom() && _limit <= _sp->end(), "sweep _limit out of bounds"); + assert(addr < _sp->end(), "addr out of bounds"); // help the closure application finish - return pointer_delta(_sp->end(), _limit); + return pointer_delta(_sp->end(), addr); } - assert(addr <= _limit, "sweep invariant"); + assert(addr < _limit, "sweep invariant"); // check if we should yield do_yield_check(addr); @@ -9121,3 +9203,57 @@ size_t MarkDeadObjectsClosure::do_blk(HeapWord* addr) { } return res; } + +TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(CMSCollector::CollectorState phase): TraceMemoryManagerStats() { + + switch (phase) { + case CMSCollector::InitialMarking: + initialize(true /* fullGC */ , + true /* recordGCBeginTime */, + true /* recordPreGCUsage */, + false /* recordPeakUsage */, + false /* recordPostGCusage */, + true /* recordAccumulatedGCTime */, + false /* recordGCEndTime */, + false /* countCollection */ ); + break; + + case CMSCollector::FinalMarking: + initialize(true /* fullGC */ , + false /* recordGCBeginTime */, + false /* recordPreGCUsage */, + false /* recordPeakUsage */, + false /* recordPostGCusage */, + true /* recordAccumulatedGCTime */, + false /* recordGCEndTime */, + false /* countCollection */ ); + break; + + case CMSCollector::Sweeping: + initialize(true /* fullGC */ , + false /* recordGCBeginTime */, + false /* recordPreGCUsage */, + true /* recordPeakUsage */, + true /* recordPostGCusage */, + false /* recordAccumulatedGCTime */, + true /* recordGCEndTime */, + true /* countCollection */ ); + break; + + default: + ShouldNotReachHere(); + } +} + +// when bailing out of cms in concurrent mode failure +TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(): TraceMemoryManagerStats() { + initialize(true /* fullGC */ , + true /* recordGCBeginTime */, + true /* recordPreGCUsage */, + true /* recordPeakUsage */, + true /* recordPostGCusage */, + true /* recordAccumulatedGCTime */, + true /* recordGCEndTime */, + true /* countCollection */ ); +} + diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp index 451538472fd..3302d78a906 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp @@ -252,12 +252,13 @@ class ModUnionClosurePar: public ModUnionClosure { class ChunkArray: public CHeapObj { size_t _index; size_t _capacity; + size_t _overflows; HeapWord** _array; // storage for array public: - ChunkArray() : _index(0), _capacity(0), _array(NULL) {} + ChunkArray() : _index(0), _capacity(0), _overflows(0), _array(NULL) {} ChunkArray(HeapWord** a, size_t c): - _index(0), _capacity(c), _array(a) {} + _index(0), _capacity(c), _overflows(0), _array(a) {} HeapWord** array() { return _array; } void set_array(HeapWord** a) { _array = a; } @@ -266,7 +267,9 @@ class ChunkArray: public CHeapObj { void set_capacity(size_t c) { _capacity = c; } size_t end() { - assert(_index < capacity(), "_index out of bounds"); + assert(_index <= capacity(), + err_msg("_index (" SIZE_FORMAT ") > _capacity (" SIZE_FORMAT "): out of bounds", + _index, _capacity)); return _index; } // exclusive @@ -277,12 +280,23 @@ class ChunkArray: public CHeapObj { void reset() { _index = 0; + if (_overflows > 0 && PrintCMSStatistics > 1) { + warning("CMS: ChunkArray[" SIZE_FORMAT "] overflowed " SIZE_FORMAT " times", + _capacity, _overflows); + } + _overflows = 0; } void record_sample(HeapWord* p, size_t sz) { // For now we do not do anything with the size if (_index < _capacity) { _array[_index++] = p; + } else { + ++_overflows; + assert(_index == _capacity, + err_msg("_index (" SIZE_FORMAT ") > _capacity (" SIZE_FORMAT + "): out of bounds at overflow#" SIZE_FORMAT, + _index, _capacity, _overflows)); } } }; @@ -507,6 +521,7 @@ class CMSCollector: public CHeapObj { friend class VM_CMS_Operation; friend class VM_CMS_Initial_Mark; friend class VM_CMS_Final_Remark; + friend class TraceCMSMemoryManagerStats; private: jlong _time_of_last_gc; @@ -1009,10 +1024,10 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { // Non-product stat counters NOT_PRODUCT( - int _numObjectsPromoted; - int _numWordsPromoted; - int _numObjectsAllocated; - int _numWordsAllocated; + size_t _numObjectsPromoted; + size_t _numWordsPromoted; + size_t _numObjectsAllocated; + size_t _numWordsAllocated; ) // Used for sizing decisions @@ -1858,3 +1873,11 @@ public: _dead_bit_map(dead_bit_map) {} size_t do_blk(HeapWord* addr); }; + +class TraceCMSMemoryManagerStats : public TraceMemoryManagerStats { + + public: + TraceCMSMemoryManagerStats(CMSCollector::CollectorState phase); + TraceCMSMemoryManagerStats(); +}; + diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp index 19e3c1c0dd2..760fabf434e 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,15 +110,21 @@ class FreeChunk VALUE_OBJ_CLASS_SPEC { } void linkNext(FreeChunk* ptr) { _next = ptr; } void linkPrev(FreeChunk* ptr) { - LP64_ONLY(if (UseCompressedOops) _prev = ptr; else) - _prev = (FreeChunk*)((intptr_t)ptr | 0x1); + LP64_ONLY(if (UseCompressedOops) _prev = ptr; else) + _prev = (FreeChunk*)((intptr_t)ptr | 0x1); } void clearPrev() { _prev = NULL; } void clearNext() { _next = NULL; } void markNotFree() { - LP64_ONLY(if (UseCompressedOops) set_mark(markOopDesc::prototype());) - // Also set _prev to null - _prev = NULL; + // Set _prev (klass) to null before (if) clearing the mark word below + _prev = NULL; +#ifdef _LP64 + if (UseCompressedOops) { + OrderAccess::storestore(); + set_mark(markOopDesc::prototype()); + } +#endif + assert(!isFree(), "Error"); } // Return the address past the end of this chunk diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp index ab9d88215d7..eebd8bb332f 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp @@ -165,13 +165,8 @@ void FreeList::removeChunk(FreeChunk*fc) { "Next of tail should be NULL"); } decrement_count(); -#define TRAP_CODE 1 -#if TRAP_CODE - if (head() == NULL) { - guarantee(tail() == NULL, "INVARIANT"); - guarantee(count() == 0, "INVARIANT"); - } -#endif + assert(((head() == NULL) + (tail() == NULL) + (count() == 0)) % 3 == 0, + "H/T/C Inconsistency"); // clear next and prev fields of fc, debug only NOT_PRODUCT( fc->linkPrev(NULL); diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp index 9b1fdf07a42..fda8624babd 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp @@ -253,8 +253,8 @@ void PromotionInfo::print_statistics(uint worker_id) const { cur_spool = cur_spool->nextSpoolBlock) { // the first entry is just a self-pointer; indices 1 through // bufferSize - 1 are occupied (thus, bufferSize - 1 slots). - guarantee((void*)cur_spool->displacedHdr == (void*)&cur_spool->displacedHdr, - "first entry of displacedHdr should be self-referential"); + assert((void*)cur_spool->displacedHdr == (void*)&cur_spool->displacedHdr, + "first entry of displacedHdr should be self-referential"); slots += cur_spool->bufferSize - 1; blocks++; } @@ -330,7 +330,7 @@ void PromotionInfo::verify() const { void PromotionInfo::print_on(outputStream* st) const { SpoolBlock* curSpool = NULL; size_t i = 0; - st->print_cr("start & end indices: [" SIZE_FORMAT ", " SIZE_FORMAT ")", + st->print_cr(" start & end indices: [" SIZE_FORMAT ", " SIZE_FORMAT ")", _firstIndex, _nextIndex); for (curSpool = _spoolHead; curSpool != _spoolTail && curSpool != NULL; curSpool = curSpool->nextSpoolBlock) { @@ -350,7 +350,7 @@ void PromotionInfo::print_on(outputStream* st) const { st->print_cr(" free "); i++; } - st->print_cr(SIZE_FORMAT " header spooling blocks", i); + st->print_cr(" " SIZE_FORMAT " header spooling blocks", i); } void SpoolBlock::print_on(outputStream* st) const { diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp index 78d3d5cb2cd..e144aa7cc86 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp @@ -339,7 +339,9 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) { return res; } -void ConcurrentG1Refine::clean_up_cache(int worker_i, G1RemSet* g1rs) { +void ConcurrentG1Refine::clean_up_cache(int worker_i, + G1RemSet* g1rs, + DirtyCardQueue* into_cset_dcq) { assert(!use_cache(), "cache should be disabled"); int start_idx; @@ -353,7 +355,19 @@ void ConcurrentG1Refine::clean_up_cache(int worker_i, G1RemSet* g1rs) { for (int i = start_idx; i < end_idx; i++) { jbyte* entry = _hot_cache[i]; if (entry != NULL) { - g1rs->concurrentRefineOneCard(entry, worker_i); + if (g1rs->concurrentRefineOneCard(entry, worker_i, true)) { + // 'entry' contains references that point into the current + // collection set. We need to record 'entry' in the DCQS + // that's used for that purpose. + // + // The only time we care about recording cards that contain + // references that point into the collection set is during + // RSet updating while within an evacuation pause. + // In this case worker_i should be the id of a GC worker thread + assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); + assert(worker_i < (int) DirtyCardQueueSet::num_par_ids(), "incorrect worker id"); + into_cset_dcq->enqueue(entry); + } } } } diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp index 85a50f7c7d5..f5c3653f888 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,7 +184,7 @@ class ConcurrentG1Refine: public CHeapObj { jbyte* cache_insert(jbyte* card_ptr, bool* defer); // Process the cached entries. - void clean_up_cache(int worker_i, G1RemSet* g1rs); + void clean_up_cache(int worker_i, G1RemSet* g1rs, DirtyCardQueue* into_cset_dcq); // Set up for parallel processing of the cards in the hot cache void clear_hot_cache_claimed_index() { diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index ddbad890dbb..4dd197ebd27 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -2586,9 +2586,6 @@ void ConcurrentMark::complete_marking_in_collection_set() { double end_time = os::elapsedTime(); double elapsed_time_ms = (end_time - start) * 1000.0; g1h->g1_policy()->record_mark_closure_time(elapsed_time_ms); - if (PrintGCDetails) { - gclog_or_tty->print_cr("Mark closure took %5.2f ms.", elapsed_time_ms); - } ClearMarksInHRClosure clr(nextMarkBitMap()); g1h->collection_set_iterate(&clr); diff --git a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp index 760f3630129..c8100c4770e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,13 +178,14 @@ DirtyCardQueueSet::get_completed_buffer(int stop_at) { } bool DirtyCardQueueSet:: -apply_closure_to_completed_buffer_helper(int worker_i, +apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl, + int worker_i, BufferNode* nd) { if (nd != NULL) { void **buf = BufferNode::make_buffer_from_node(nd); size_t index = nd->index(); bool b = - DirtyCardQueue::apply_closure_to_buffer(_closure, buf, + DirtyCardQueue::apply_closure_to_buffer(cl, buf, index, _sz, true, worker_i); if (b) { @@ -199,17 +200,24 @@ apply_closure_to_completed_buffer_helper(int worker_i, } } -bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i, +bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* cl, + int worker_i, int stop_at, - bool during_pause) -{ + bool during_pause) { assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause"); BufferNode* nd = get_completed_buffer(stop_at); - bool res = apply_closure_to_completed_buffer_helper(worker_i, nd); + bool res = apply_closure_to_completed_buffer_helper(cl, worker_i, nd); if (res) Atomic::inc(&_processed_buffers_rs_thread); return res; } +bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i, + int stop_at, + bool during_pause) { + return apply_closure_to_completed_buffer(_closure, worker_i, + stop_at, during_pause); +} + void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() { BufferNode* nd = _completed_buffers_head; while (nd != NULL) { @@ -222,8 +230,8 @@ void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() { } } -void DirtyCardQueueSet::abandon_logs() { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); +// Deallocates any completed log buffers +void DirtyCardQueueSet::clear() { BufferNode* buffers_to_delete = NULL; { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); @@ -242,6 +250,12 @@ void DirtyCardQueueSet::abandon_logs() { buffers_to_delete = nd->next(); deallocate_buffer(BufferNode::make_buffer_from_node(nd)); } + +} + +void DirtyCardQueueSet::abandon_logs() { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); + clear(); // Since abandon is done only at safepoints, we can safely manipulate // these queues. for (JavaThread* t = Threads::first(); t; t = t->next()) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp index e1b68981648..524c0c25681 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,21 @@ public: int stop_at = 0, bool during_pause = false); - bool apply_closure_to_completed_buffer_helper(int worker_i, + // If there exists some completed buffer, pop it, then apply the + // specified closure to all its elements, nulling out those elements + // processed. If all elements are processed, returns "true". If no + // completed buffers exist, returns false. If a completed buffer exists, + // but is only partially completed before a "yield" happens, the + // partially completed buffer (with its processed elements set to NULL) + // is returned to the completed buffer set, and this call returns false. + bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl, + int worker_i = 0, + int stop_at = 0, + bool during_pause = false); + + // Helper routine for the above. + bool apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl, + int worker_i, BufferNode* nd); BufferNode* get_completed_buffer(int stop_at); @@ -136,6 +150,9 @@ public: return &_shared_dirty_card_queue; } + // Deallocate any completed log buffers + void clear(); + // If a full collection is happening, reset partial logs, and ignore // completed ones: the full collection will make them all irrelevant. void abandon_logs(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 658ac777f49..07425538987 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -56,7 +56,12 @@ public: _sts(sts), _g1rs(g1rs), _cg1r(cg1r), _concurrent(true) {} bool do_card_ptr(jbyte* card_ptr, int worker_i) { - _g1rs->concurrentRefineOneCard(card_ptr, worker_i); + bool oops_into_cset = _g1rs->concurrentRefineOneCard(card_ptr, worker_i, false); + // This path is executed by the concurrent refine or mutator threads, + // concurrently, and so we do not care if card_ptr contains references + // that point into the collection set. + assert(!oops_into_cset, "should be"); + if (_concurrent && _sts->should_yield()) { // Caller will actually yield. return false; @@ -1039,29 +1044,56 @@ resize_if_necessary_after_full_collection(size_t word_size) { const size_t capacity_after_gc = capacity(); const size_t free_after_gc = capacity_after_gc - used_after_gc; + // This is enforced in arguments.cpp. + assert(MinHeapFreeRatio <= MaxHeapFreeRatio, + "otherwise the code below doesn't make sense"); + // We don't have floating point command-line arguments - const double minimum_free_percentage = (double) MinHeapFreeRatio / 100; + const double minimum_free_percentage = (double) MinHeapFreeRatio / 100.0; const double maximum_used_percentage = 1.0 - minimum_free_percentage; - const double maximum_free_percentage = (double) MaxHeapFreeRatio / 100; + const double maximum_free_percentage = (double) MaxHeapFreeRatio / 100.0; const double minimum_used_percentage = 1.0 - maximum_free_percentage; - size_t minimum_desired_capacity = (size_t) (used_after_gc / maximum_used_percentage); - size_t maximum_desired_capacity = (size_t) (used_after_gc / minimum_used_percentage); + const size_t min_heap_size = collector_policy()->min_heap_byte_size(); + const size_t max_heap_size = collector_policy()->max_heap_byte_size(); - // Don't shrink less than the initial size. - minimum_desired_capacity = - MAX2(minimum_desired_capacity, - collector_policy()->initial_heap_byte_size()); - maximum_desired_capacity = - MAX2(maximum_desired_capacity, - collector_policy()->initial_heap_byte_size()); + // We have to be careful here as these two calculations can overflow + // 32-bit size_t's. + double used_after_gc_d = (double) used_after_gc; + double minimum_desired_capacity_d = used_after_gc_d / maximum_used_percentage; + double maximum_desired_capacity_d = used_after_gc_d / minimum_used_percentage; - // We are failing here because minimum_desired_capacity is - assert(used_after_gc <= minimum_desired_capacity, "sanity check"); - assert(minimum_desired_capacity <= maximum_desired_capacity, "sanity check"); + // Let's make sure that they are both under the max heap size, which + // by default will make them fit into a size_t. + double desired_capacity_upper_bound = (double) max_heap_size; + minimum_desired_capacity_d = MIN2(minimum_desired_capacity_d, + desired_capacity_upper_bound); + maximum_desired_capacity_d = MIN2(maximum_desired_capacity_d, + desired_capacity_upper_bound); + + // We can now safely turn them into size_t's. + size_t minimum_desired_capacity = (size_t) minimum_desired_capacity_d; + size_t maximum_desired_capacity = (size_t) maximum_desired_capacity_d; + + // This assert only makes sense here, before we adjust them + // with respect to the min and max heap size. + assert(minimum_desired_capacity <= maximum_desired_capacity, + err_msg("minimum_desired_capacity = "SIZE_FORMAT", " + "maximum_desired_capacity = "SIZE_FORMAT, + minimum_desired_capacity, maximum_desired_capacity)); + + // Should not be greater than the heap max size. No need to adjust + // it with respect to the heap min size as it's a lower bound (i.e., + // we'll try to make the capacity larger than it, not smaller). + minimum_desired_capacity = MIN2(minimum_desired_capacity, max_heap_size); + // Should not be less than the heap min size. No need to adjust it + // with respect to the heap max size as it's an upper bound (i.e., + // we'll try to make the capacity smaller than it, not greater). + maximum_desired_capacity = MAX2(maximum_desired_capacity, min_heap_size); if (PrintGC && Verbose) { - const double free_percentage = ((double)free_after_gc) / capacity(); + const double free_percentage = + (double) free_after_gc / (double) capacity_after_gc; gclog_or_tty->print_cr("Computing new size after full GC "); gclog_or_tty->print_cr(" " " minimum_free_percentage: %6.2f", @@ -1073,45 +1105,47 @@ resize_if_necessary_after_full_collection(size_t word_size) { " capacity: %6.1fK" " minimum_desired_capacity: %6.1fK" " maximum_desired_capacity: %6.1fK", - capacity() / (double) K, - minimum_desired_capacity / (double) K, - maximum_desired_capacity / (double) K); + (double) capacity_after_gc / (double) K, + (double) minimum_desired_capacity / (double) K, + (double) maximum_desired_capacity / (double) K); gclog_or_tty->print_cr(" " - " free_after_gc : %6.1fK" - " used_after_gc : %6.1fK", - free_after_gc / (double) K, - used_after_gc / (double) K); + " free_after_gc: %6.1fK" + " used_after_gc: %6.1fK", + (double) free_after_gc / (double) K, + (double) used_after_gc / (double) K); gclog_or_tty->print_cr(" " " free_percentage: %6.2f", free_percentage); } - if (capacity() < minimum_desired_capacity) { + if (capacity_after_gc < minimum_desired_capacity) { // Don't expand unless it's significant size_t expand_bytes = minimum_desired_capacity - capacity_after_gc; expand(expand_bytes); if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" expanding:" + gclog_or_tty->print_cr(" " + " expanding:" + " max_heap_size: %6.1fK" " minimum_desired_capacity: %6.1fK" " expand_bytes: %6.1fK", - minimum_desired_capacity / (double) K, - expand_bytes / (double) K); + (double) max_heap_size / (double) K, + (double) minimum_desired_capacity / (double) K, + (double) expand_bytes / (double) K); } // No expansion, now see if we want to shrink - } else if (capacity() > maximum_desired_capacity) { + } else if (capacity_after_gc > maximum_desired_capacity) { // Capacity too large, compute shrinking size size_t shrink_bytes = capacity_after_gc - maximum_desired_capacity; shrink(shrink_bytes); if (PrintGC && Verbose) { gclog_or_tty->print_cr(" " " shrinking:" - " initSize: %.1fK" - " maximum_desired_capacity: %.1fK", - collector_policy()->initial_heap_byte_size() / (double) K, - maximum_desired_capacity / (double) K); - gclog_or_tty->print_cr(" " - " shrink_bytes: %.1fK", - shrink_bytes / (double) K); + " min_heap_size: %6.1fK" + " maximum_desired_capacity: %6.1fK" + " shrink_bytes: %6.1fK", + (double) min_heap_size / (double) K, + (double) maximum_desired_capacity / (double) K, + (double) shrink_bytes / (double) K); } } } @@ -1322,6 +1356,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : SharedHeap(policy_), _g1_policy(policy_), _dirty_card_queue_set(false), + _into_cset_dirty_card_queue_set(false), _ref_processor(NULL), _process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)), _bot_shared(NULL), @@ -1572,6 +1607,16 @@ jint G1CollectedHeap::initialize() { Shared_DirtyCardQ_lock, &JavaThread::dirty_card_queue_set()); } + + // Initialize the card queue set used to hold cards containing + // references into the collection set. + _into_cset_dirty_card_queue_set.initialize(DirtyCardQ_CBL_mon, + DirtyCardQ_FL_lock, + -1, // never trigger processing + -1, // no limit on length + Shared_DirtyCardQ_lock, + &JavaThread::dirty_card_queue_set()); + // In case we're keeping closure specialization stats, initialize those // counts and that mechanism. SpecializationStats::clear(); @@ -1603,14 +1648,16 @@ size_t G1CollectedHeap::capacity() const { return _g1_committed.byte_size(); } -void G1CollectedHeap::iterate_dirty_card_closure(bool concurrent, +void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl, + DirtyCardQueue* into_cset_dcq, + bool concurrent, int worker_i) { // Clean cards in the hot card cache - concurrent_g1_refine()->clean_up_cache(worker_i, g1_rem_set()); + concurrent_g1_refine()->clean_up_cache(worker_i, g1_rem_set(), into_cset_dcq); DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); int n_completed_buffers = 0; - while (dcqs.apply_closure_to_completed_buffer(worker_i, 0, true)) { + while (dcqs.apply_closure_to_completed_buffer(cl, worker_i, 0, true)) { n_completed_buffers++; } g1_policy()->record_update_rs_processed_buffers(worker_i, @@ -2147,9 +2194,12 @@ size_t G1CollectedHeap::unsafe_max_tlab_alloc(Thread* ignored) const { } } -HeapWord* G1CollectedHeap::allocate_new_tlab(size_t size) { +HeapWord* G1CollectedHeap::allocate_new_tlab(size_t word_size) { + assert(!isHumongous(word_size), + err_msg("a TLAB should not be of humongous size, " + "word_size = "SIZE_FORMAT, word_size)); bool dummy; - return G1CollectedHeap::mem_allocate(size, false, true, &dummy); + return G1CollectedHeap::mem_allocate(word_size, false, true, &dummy); } bool G1CollectedHeap::allocs_are_zero_filled() { @@ -2692,6 +2742,35 @@ struct PrepareForRSScanningClosure : public HeapRegionClosure { } }; +#if TASKQUEUE_STATS +void G1CollectedHeap::print_taskqueue_stats_hdr(outputStream* const st) { + st->print_raw_cr("GC Task Stats"); + st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr(); + st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr(); +} + +void G1CollectedHeap::print_taskqueue_stats(outputStream* const st) const { + print_taskqueue_stats_hdr(st); + + TaskQueueStats totals; + const int n = workers() != NULL ? workers()->total_workers() : 1; + for (int i = 0; i < n; ++i) { + st->print("%3d ", i); task_queue(i)->stats.print(st); st->cr(); + totals += task_queue(i)->stats; + } + st->print_raw("tot "); totals.print(st); st->cr(); + + DEBUG_ONLY(totals.verify()); +} + +void G1CollectedHeap::reset_taskqueue_stats() { + const int n = workers() != NULL ? workers()->total_workers() : 1; + for (int i = 0; i < n; ++i) { + task_queue(i)->stats.reset(); + } +} +#endif // TASKQUEUE_STATS + void G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { if (GC_locker::check_active_before_gc()) { @@ -2825,93 +2904,57 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { g1_policy()->print_collection_set(g1_policy()->inc_cset_head(), gclog_or_tty); #endif // YOUNG_LIST_VERBOSE - // Now choose the CS. We may abandon a pause if we find no - // region that will fit in the MMU pause. - bool abandoned = g1_policy()->choose_collection_set(target_pause_time_ms); + g1_policy()->choose_collection_set(target_pause_time_ms); // Nothing to do if we were unable to choose a collection set. - if (!abandoned) { #if G1_REM_SET_LOGGING - gclog_or_tty->print_cr("\nAfter pause, heap:"); - print(); + gclog_or_tty->print_cr("\nAfter pause, heap:"); + print(); #endif - PrepareForRSScanningClosure prepare_for_rs_scan; - collection_set_iterate(&prepare_for_rs_scan); + PrepareForRSScanningClosure prepare_for_rs_scan; + collection_set_iterate(&prepare_for_rs_scan); - setup_surviving_young_words(); + setup_surviving_young_words(); - // Set up the gc allocation regions. - get_gc_alloc_regions(); + // Set up the gc allocation regions. + get_gc_alloc_regions(); - // Actually do the work... - evacuate_collection_set(); + // Actually do the work... + evacuate_collection_set(); - free_collection_set(g1_policy()->collection_set()); - g1_policy()->clear_collection_set(); + free_collection_set(g1_policy()->collection_set()); + g1_policy()->clear_collection_set(); - cleanup_surviving_young_words(); + cleanup_surviving_young_words(); - // Start a new incremental collection set for the next pause. - g1_policy()->start_incremental_cset_building(); + // Start a new incremental collection set for the next pause. + g1_policy()->start_incremental_cset_building(); - // Clear the _cset_fast_test bitmap in anticipation of adding - // regions to the incremental collection set for the next - // evacuation pause. - clear_cset_fast_test(); + // Clear the _cset_fast_test bitmap in anticipation of adding + // regions to the incremental collection set for the next + // evacuation pause. + clear_cset_fast_test(); - if (g1_policy()->in_young_gc_mode()) { - _young_list->reset_sampled_info(); + if (g1_policy()->in_young_gc_mode()) { + _young_list->reset_sampled_info(); - // Don't check the whole heap at this point as the - // GC alloc regions from this pause have been tagged - // as survivors and moved on to the survivor list. - // Survivor regions will fail the !is_young() check. - assert(check_young_list_empty(false /* check_heap */), - "young list should be empty"); + // Don't check the whole heap at this point as the + // GC alloc regions from this pause have been tagged + // as survivors and moved on to the survivor list. + // Survivor regions will fail the !is_young() check. + assert(check_young_list_empty(false /* check_heap */), + "young list should be empty"); #if YOUNG_LIST_VERBOSE - gclog_or_tty->print_cr("Before recording survivors.\nYoung List:"); - _young_list->print(); + gclog_or_tty->print_cr("Before recording survivors.\nYoung List:"); + _young_list->print(); #endif // YOUNG_LIST_VERBOSE - g1_policy()->record_survivor_regions(_young_list->survivor_length(), + g1_policy()->record_survivor_regions(_young_list->survivor_length(), _young_list->first_survivor_region(), _young_list->last_survivor_region()); - _young_list->reset_auxilary_lists(); - } - } else { - // We have abandoned the current collection. This can only happen - // if we're not doing young or partially young collections, and - // we didn't find an old region that we're able to collect within - // the allowed time. - - assert(g1_policy()->collection_set() == NULL, "should be"); - assert(_young_list->length() == 0, "because it should be"); - - // This should be a no-op. - abandon_collection_set(g1_policy()->inc_cset_head()); - - g1_policy()->clear_incremental_cset(); - g1_policy()->stop_incremental_cset_building(); - - // Start a new incremental collection set for the next pause. - g1_policy()->start_incremental_cset_building(); - - // Clear the _cset_fast_test bitmap in anticipation of adding - // regions to the incremental collection set for the next - // evacuation pause. - clear_cset_fast_test(); - - // This looks confusing, because the DPT should really be empty - // at this point -- since we have not done any collection work, - // there should not be any derived pointers in the table to update; - // however, there is some additional state in the DPT which is - // reset at the end of the (null) "gc" here via the following call. - // A better approach might be to split off that state resetting work - // into a separate method that asserts that the DPT is empty and call - // that here. That is deferred for now. - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); + _young_list->reset_auxilary_lists(); } if (evacuation_failed()) { @@ -2945,7 +2988,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { double end_time_sec = os::elapsedTime(); double pause_time_ms = (end_time_sec - start_time_sec) * MILLIUNITS; g1_policy()->record_pause_time_ms(pause_time_ms); - g1_policy()->record_collection_pause_end(abandoned); + g1_policy()->record_collection_pause_end(); assert(regions_accounted_for(), "Region leakage."); @@ -2988,6 +3031,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { } } + TASKQUEUE_STATS_ONLY(if (ParallelGCVerbose) print_taskqueue_stats()); + TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); + if (PrintHeapAtGC) { Universe::print_heap_after_gc(); } @@ -3346,25 +3392,6 @@ public: } }; -class UpdateRSetImmediate : public OopsInHeapRegionClosure { -private: - G1CollectedHeap* _g1; - G1RemSet* _g1_rem_set; -public: - UpdateRSetImmediate(G1CollectedHeap* g1) : - _g1(g1), _g1_rem_set(g1->g1_rem_set()) {} - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - template void do_oop_work(T* p) { - assert(_from->is_in_reserved(p), "paranoia"); - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop) && !_from->is_survivor()) { - _g1_rem_set->par_write_ref(_from, p, 0); - } - } -}; - class UpdateRSetDeferred : public OopsInHeapRegionClosure { private: G1CollectedHeap* _g1; @@ -3389,8 +3416,6 @@ public: } }; - - class RemoveSelfPointerClosure: public ObjectClosure { private: G1CollectedHeap* _g1; @@ -3453,7 +3478,7 @@ public: }; void G1CollectedHeap::remove_self_forwarding_pointers() { - UpdateRSetImmediate immediate_update(_g1h); + UpdateRSetImmediate immediate_update(_g1h->g1_rem_set()); DirtyCardQueue dcq(&_g1h->dirty_card_queue_set()); UpdateRSetDeferred deferred_update(_g1h, &dcq); OopsInHeapRegionClosure *cl; @@ -3583,7 +3608,7 @@ void G1CollectedHeap::handle_evacuation_failure_common(oop old, markOop m) { if (!r->evacuation_failed()) { r->set_evacuation_failed(true); if (G1PrintHeapRegions) { - gclog_or_tty->print("evacuation failed in heap region "PTR_FORMAT" " + gclog_or_tty->print("overflow in heap region "PTR_FORMAT" " "["PTR_FORMAT","PTR_FORMAT")\n", r, r->bottom(), r->end()); } @@ -3617,6 +3642,10 @@ void G1CollectedHeap::preserve_mark_if_necessary(oop obj, markOop m) { HeapWord* G1CollectedHeap::par_allocate_during_gc(GCAllocPurpose purpose, size_t word_size) { + assert(!isHumongous(word_size), + err_msg("we should not be seeing humongous allocation requests " + "during GC, word_size = "SIZE_FORMAT, word_size)); + HeapRegion* alloc_region = _gc_alloc_regions[purpose]; // let the caller handle alloc failure if (alloc_region == NULL) return NULL; @@ -3649,6 +3678,10 @@ G1CollectedHeap::allocate_during_gc_slow(GCAllocPurpose purpose, HeapRegion* alloc_region, bool par, size_t word_size) { + assert(!isHumongous(word_size), + err_msg("we should not be seeing humongous allocation requests " + "during GC, word_size = "SIZE_FORMAT, word_size)); + HeapWord* block = NULL; // In the parallel case, a previous thread to obtain the lock may have // already assigned a new gc_alloc_region. @@ -3754,10 +3787,6 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, int queue_num) _surviving_alloc_buffer(g1h->desired_plab_sz(GCAllocForSurvived)), _tenured_alloc_buffer(g1h->desired_plab_sz(GCAllocForTenured)), _age_table(false), -#if G1_DETAILED_STATS - _pushes(0), _pops(0), _steals(0), - _steal_attempts(0), _overflow_pushes(0), -#endif _strong_roots_time(0), _term_time(0), _alloc_buffer_waste(0), _undo_waste(0) { @@ -3777,14 +3806,41 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, int queue_num) _surviving_young_words = _surviving_young_words_base + PADDING_ELEM_NUM; memset(_surviving_young_words, 0, real_length * sizeof(size_t)); - _overflowed_refs = new OverflowQueue(10); - _alloc_buffers[GCAllocForSurvived] = &_surviving_alloc_buffer; _alloc_buffers[GCAllocForTenured] = &_tenured_alloc_buffer; _start = os::elapsedTime(); } +void +G1ParScanThreadState::print_termination_stats_hdr(outputStream* const st) +{ + st->print_raw_cr("GC Termination Stats"); + st->print_raw_cr(" elapsed --strong roots-- -------termination-------" + " ------waste (KiB)------"); + st->print_raw_cr("thr ms ms % ms % attempts" + " total alloc undo"); + st->print_raw_cr("--- --------- --------- ------ --------- ------ --------" + " ------- ------- -------"); +} + +void +G1ParScanThreadState::print_termination_stats(int i, + outputStream* const st) const +{ + const double elapsed_ms = elapsed_time() * 1000.0; + const double s_roots_ms = strong_roots_time() * 1000.0; + const double term_ms = term_time() * 1000.0; + st->print_cr("%3d %9.2f %9.2f %6.2f " + "%9.2f %6.2f " SIZE_FORMAT_W(8) " " + SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7), + i, elapsed_ms, s_roots_ms, s_roots_ms * 100 / elapsed_ms, + term_ms, term_ms * 100 / elapsed_ms, term_attempts(), + (alloc_buffer_waste() + undo_waste()) * HeapWordSize / K, + alloc_buffer_waste() * HeapWordSize / K, + undo_waste() * HeapWordSize / K); +} + G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : _g1(g1), _g1_rem(_g1->g1_rem_set()), _cm(_g1->concurrent_mark()), _par_scan_state(par_scan_state) { } @@ -3991,12 +4047,9 @@ public: G1ParScanThreadState* pss = par_scan_state(); while (true) { pss->trim_queue(); - IF_G1_DETAILED_STATS(pss->note_steal_attempt()); StarTask stolen_task; if (queues()->steal(pss->queue_num(), pss->hash_seed(), stolen_task)) { - IF_G1_DETAILED_STATS(pss->note_steal()); - // slightly paranoid tests; I'm trying to catch potential // problems before we go into push_on_queue to know where the // problem is coming from @@ -4115,35 +4168,9 @@ public: // Clean up any par-expanded rem sets. HeapRegionRemSet::par_cleanup(); - MutexLocker x(stats_lock()); if (ParallelGCVerbose) { - gclog_or_tty->print("Thread %d complete:\n", i); -#if G1_DETAILED_STATS - gclog_or_tty->print(" Pushes: %7d Pops: %7d Overflows: %7d Steals %7d (in %d attempts)\n", - pss.pushes(), - pss.pops(), - pss.overflow_pushes(), - pss.steals(), - pss.steal_attempts()); -#endif - double elapsed = pss.elapsed(); - double strong_roots = pss.strong_roots_time(); - double term = pss.term_time(); - gclog_or_tty->print(" Elapsed: %7.2f ms.\n" - " Strong roots: %7.2f ms (%6.2f%%)\n" - " Termination: %7.2f ms (%6.2f%%) " - "(in "SIZE_FORMAT" entries)\n", - elapsed * 1000.0, - strong_roots * 1000.0, (strong_roots*100.0/elapsed), - term * 1000.0, (term*100.0/elapsed), - pss.term_attempts()); - size_t total_waste = pss.alloc_buffer_waste() + pss.undo_waste(); - gclog_or_tty->print(" Waste: %8dK\n" - " Alloc Buffer: %8dK\n" - " Undo: %8dK\n", - (total_waste * HeapWordSize) / K, - (pss.alloc_buffer_waste() * HeapWordSize) / K, - (pss.undo_waste() * HeapWordSize) / K); + MutexLocker x(stats_lock()); + pss.print_termination_stats(i); } assert(pss.refs_to_scan() == 0, "Task queue should be empty"); @@ -4260,6 +4287,7 @@ void G1CollectedHeap::evacuate_collection_set() { if (ParallelGCThreads > 0) { // The individual threads will set their evac-failure closures. StrongRootsScope srs(this); + if (ParallelGCVerbose) G1ParScanThreadState::print_termination_stats_hdr(); workers()->run_task(&g1_par_task); } else { StrongRootsScope srs(this); @@ -4293,7 +4321,7 @@ void G1CollectedHeap::evacuate_collection_set() { if (evacuation_failed()) { remove_self_forwarding_pointers(); if (PrintGCDetails) { - gclog_or_tty->print(" (evacuation failed)"); + gclog_or_tty->print(" (to-space overflow)"); } else if (PrintGC) { gclog_or_tty->print("--"); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 74606c18bdf..a342d698d3b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -46,17 +46,7 @@ class ConcurrentMarkThread; class ConcurrentG1Refine; class ConcurrentZFThread; -// If want to accumulate detailed statistics on work queues -// turn this on. -#define G1_DETAILED_STATS 0 - -#if G1_DETAILED_STATS -# define IF_G1_DETAILED_STATS(code) code -#else -# define IF_G1_DETAILED_STATS(code) -#endif - -typedef GenericTaskQueue RefToScanQueue; +typedef OverflowTaskQueue RefToScanQueue; typedef GenericTaskQueueSet RefToScanQueueSet; typedef int RegionIdx_t; // needs to hold [ 0..max_regions() ) @@ -471,6 +461,12 @@ protected: virtual void shrink(size_t expand_bytes); void shrink_helper(size_t expand_bytes); + #if TASKQUEUE_STATS + static void print_taskqueue_stats_hdr(outputStream* const st = gclog_or_tty); + void print_taskqueue_stats(outputStream* const st = gclog_or_tty) const; + void reset_taskqueue_stats(); + #endif // TASKQUEUE_STATS + // Do an incremental collection: identify a collection set, and evacuate // its live objects elsewhere. virtual void do_collection_pause(); @@ -505,6 +501,12 @@ protected: // A function to check the consistency of dirty card logs. void check_ct_logs_at_safepoint(); + // A DirtyCardQueueSet that is used to hold cards that contain + // references into the current collection set. This is used to + // update the remembered sets of the regions in the collection + // set in the event of an evacuation failure. + DirtyCardQueueSet _into_cset_dirty_card_queue_set; + // After a collection pause, make the regions in the CS into free // regions. void free_collection_set(HeapRegion* cs_head); @@ -656,11 +658,18 @@ protected: public: void set_refine_cte_cl_concurrency(bool concurrent); - RefToScanQueue *task_queue(int i); + RefToScanQueue *task_queue(int i) const; // A set of cards where updates happened during the GC DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; } + // A DirtyCardQueueSet that is used to hold cards that contain + // references into the current collection set. This is used to + // update the remembered sets of the regions in the collection + // set in the event of an evacuation failure. + DirtyCardQueueSet& into_cset_dirty_card_queue_set() + { return _into_cset_dirty_card_queue_set; } + // Create a G1CollectedHeap with the specified policy. // Must call the initialize method afterwards. // May not return if something goes wrong. @@ -715,7 +724,9 @@ public: OrderAccess::fence(); } - void iterate_dirty_card_closure(bool concurrent, int worker_i); + void iterate_dirty_card_closure(CardTableEntryClosure* cl, + DirtyCardQueue* into_cset_dcq, + bool concurrent, int worker_i); // The shared block offset table array. G1BlockOffsetSharedArray* bot_shared() const { return _bot_shared; } @@ -1021,7 +1032,7 @@ public: virtual bool supports_tlab_allocation() const; virtual size_t tlab_capacity(Thread* thr) const; virtual size_t unsafe_max_tlab_alloc(Thread* thr) const; - virtual HeapWord* allocate_new_tlab(size_t size); + virtual HeapWord* allocate_new_tlab(size_t word_size); // Can a compiler initialize a new object without store barriers? // This permission only extends from the creation of a new object @@ -1564,9 +1575,6 @@ protected: CardTableModRefBS* _ct_bs; G1RemSet* _g1_rem; - typedef GrowableArray OverflowQueue; - OverflowQueue* _overflowed_refs; - G1ParGCAllocBuffer _surviving_alloc_buffer; G1ParGCAllocBuffer _tenured_alloc_buffer; G1ParGCAllocBuffer* _alloc_buffers[GCAllocPurposeCount]; @@ -1583,10 +1591,6 @@ protected: int _queue_num; size_t _term_attempts; -#if G1_DETAILED_STATS - int _pushes, _pops, _steals, _steal_attempts; - int _overflow_pushes; -#endif double _start; double _start_strong_roots; @@ -1600,7 +1604,7 @@ protected: // this points into the array, as we use the first few entries for padding size_t* _surviving_young_words; -#define PADDING_ELEM_NUM (64 / sizeof(size_t)) +#define PADDING_ELEM_NUM (DEFAULT_CACHE_LINE_SIZE / sizeof(size_t)) void add_to_alloc_buffer_waste(size_t waste) { _alloc_buffer_waste += waste; } @@ -1635,15 +1639,14 @@ public: } RefToScanQueue* refs() { return _refs; } - OverflowQueue* overflowed_refs() { return _overflowed_refs; } ageTable* age_table() { return &_age_table; } G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose) { return _alloc_buffers[purpose]; } - size_t alloc_buffer_waste() { return _alloc_buffer_waste; } - size_t undo_waste() { return _undo_waste; } + size_t alloc_buffer_waste() const { return _alloc_buffer_waste; } + size_t undo_waste() const { return _undo_waste; } template void push_on_queue(T* ref) { assert(ref != NULL, "invariant"); @@ -1656,12 +1659,7 @@ public: assert(_g1h->obj_in_cs(p), "Should be in CS"); } #endif - if (!refs()->push(ref)) { - overflowed_refs()->push(ref); - IF_G1_DETAILED_STATS(note_overflow_push()); - } else { - IF_G1_DETAILED_STATS(note_push()); - } + refs()->push(ref); } void pop_from_queue(StarTask& ref) { @@ -1672,7 +1670,6 @@ public: _g1h->is_in_g1_reserved(ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)ref) : oopDesc::load_decode_heap_oop((oop*)ref)), "invariant"); - IF_G1_DETAILED_STATS(note_pop()); } else { StarTask null_task; ref = null_task; @@ -1680,7 +1677,8 @@ public: } void pop_from_overflow_queue(StarTask& ref) { - StarTask new_ref = overflowed_refs()->pop(); + StarTask new_ref; + refs()->pop_overflow(new_ref); assert((oop*)new_ref != NULL, "pop() from a local non-empty stack"); assert(UseCompressedOops || !new_ref.is_narrow(), "Error"); assert(has_partial_array_mask((oop*)new_ref) || @@ -1690,8 +1688,8 @@ public: ref = new_ref; } - int refs_to_scan() { return refs()->size(); } - int overflowed_refs_to_scan() { return overflowed_refs()->length(); } + int refs_to_scan() { return refs()->size(); } + int overflowed_refs_to_scan() { return refs()->overflow_stack()->length(); } template void update_rs(HeapRegion* from, T* p, int tid) { if (G1DeferredRSUpdate) { @@ -1760,30 +1758,16 @@ public: int* hash_seed() { return &_hash_seed; } int queue_num() { return _queue_num; } - size_t term_attempts() { return _term_attempts; } + size_t term_attempts() const { return _term_attempts; } void note_term_attempt() { _term_attempts++; } -#if G1_DETAILED_STATS - int pushes() { return _pushes; } - int pops() { return _pops; } - int steals() { return _steals; } - int steal_attempts() { return _steal_attempts; } - int overflow_pushes() { return _overflow_pushes; } - - void note_push() { _pushes++; } - void note_pop() { _pops++; } - void note_steal() { _steals++; } - void note_steal_attempt() { _steal_attempts++; } - void note_overflow_push() { _overflow_pushes++; } -#endif - void start_strong_roots() { _start_strong_roots = os::elapsedTime(); } void end_strong_roots() { _strong_roots_time += (os::elapsedTime() - _start_strong_roots); } - double strong_roots_time() { return _strong_roots_time; } + double strong_roots_time() const { return _strong_roots_time; } void start_term_time() { note_term_attempt(); @@ -1792,12 +1776,17 @@ public: void end_term_time() { _term_time += (os::elapsedTime() - _start_term); } - double term_time() { return _term_time; } + double term_time() const { return _term_time; } - double elapsed() { + double elapsed_time() const { return os::elapsedTime() - _start; } + static void + print_termination_stats_hdr(outputStream* const st = gclog_or_tty); + void + print_termination_stats(int i, outputStream* const st = gclog_or_tty) const; + size_t* surviving_young_words() { // We add on to hide entry 0 which accumulates surviving words for // age -1 regions (i.e. non-young ones) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp index a2459d9d0aa..c4eb0388417 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp @@ -57,8 +57,9 @@ inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size, assert( SafepointSynchronize::is_at_safepoint() || Heap_lock->owned_by_self(), "pre-condition of the call" ); - if (_cur_alloc_region != NULL) { - + // All humongous allocation requests should go through the slow path in + // attempt_allocation_slow(). + if (!isHumongous(word_size) && _cur_alloc_region != NULL) { // If this allocation causes a region to become non empty, // then we need to update our free_regions count. @@ -69,23 +70,23 @@ inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size, } else { res = _cur_alloc_region->allocate(word_size); } - } - if (res != NULL) { - if (!SafepointSynchronize::is_at_safepoint()) { - assert( Heap_lock->owned_by_self(), "invariant" ); - Heap_lock->unlock(); + + if (res != NULL) { + if (!SafepointSynchronize::is_at_safepoint()) { + assert( Heap_lock->owned_by_self(), "invariant" ); + Heap_lock->unlock(); + } + return res; } - return res; } // attempt_allocation_slow will also unlock the heap lock when appropriate. return attempt_allocation_slow(word_size, permit_collection_pause); } -inline RefToScanQueue* G1CollectedHeap::task_queue(int i) { +inline RefToScanQueue* G1CollectedHeap::task_queue(int i) const { return _task_queues->queue(i); } - inline bool G1CollectedHeap::isMarkedPrev(oop obj) const { return _cm->prevMarkBitMap()->isMarked((HeapWord *)obj); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 0cb73eb0c6b..4f8e5d1520a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -88,7 +88,6 @@ G1CollectorPolicy::G1CollectorPolicy() : _all_mod_union_times_ms(new NumberSeq()), _summary(new Summary()), - _abandoned_summary(new AbandonedSummary()), #ifndef PRODUCT _cur_clear_ct_time_ms(0.0), @@ -238,7 +237,6 @@ G1CollectorPolicy::G1CollectorPolicy() : _par_last_update_rs_processed_buffers = new double[_parallel_gc_threads]; _par_last_scan_rs_times_ms = new double[_parallel_gc_threads]; - _par_last_scan_new_refs_times_ms = new double[_parallel_gc_threads]; _par_last_obj_copy_times_ms = new double[_parallel_gc_threads]; @@ -842,7 +840,6 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec, _par_last_update_rs_times_ms[i] = -1234.0; _par_last_update_rs_processed_buffers[i] = -1234.0; _par_last_scan_rs_times_ms[i] = -1234.0; - _par_last_scan_new_refs_times_ms[i] = -1234.0; _par_last_obj_copy_times_ms[i] = -1234.0; _par_last_termination_times_ms[i] = -1234.0; _par_last_termination_attempts[i] = -1234.0; @@ -1126,7 +1123,7 @@ double G1CollectorPolicy::max_sum (double* data1, // Anything below that is considered to be zero #define MIN_TIMER_GRANULARITY 0.0000001 -void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { +void G1CollectorPolicy::record_collection_pause_end() { double end_time_sec = os::elapsedTime(); double elapsed_ms = _last_pause_time_ms; bool parallel = ParallelGCThreads > 0; @@ -1136,7 +1133,7 @@ void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { size_t cur_used_bytes = _g1->used(); assert(cur_used_bytes == _g1->recalculate_used(), "It should!"); bool last_pause_included_initial_mark = false; - bool update_stats = !abandoned && !_g1->evacuation_failed(); + bool update_stats = !_g1->evacuation_failed(); #ifndef PRODUCT if (G1YoungSurvRateVerbose) { @@ -1275,12 +1272,7 @@ void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { gclog_or_tty->print_cr(" Recording collection pause(%d)", _n_pauses); } - PauseSummary* summary; - if (abandoned) { - summary = _abandoned_summary; - } else { - summary = _summary; - } + PauseSummary* summary = _summary; double ext_root_scan_time = avg_value(_par_last_ext_root_scan_times_ms); double mark_stack_scan_time = avg_value(_par_last_mark_stack_scan_times_ms); @@ -1348,61 +1340,58 @@ void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { double other_time_ms = elapsed_ms; - if (!abandoned) { - if (_satb_drain_time_set) - other_time_ms -= _cur_satb_drain_time_ms; + if (_satb_drain_time_set) { + other_time_ms -= _cur_satb_drain_time_ms; + } - if (parallel) - other_time_ms -= _cur_collection_par_time_ms + _cur_clear_ct_time_ms; - else - other_time_ms -= - update_rs_time + - ext_root_scan_time + mark_stack_scan_time + - scan_rs_time + obj_copy_time; + if (parallel) { + other_time_ms -= _cur_collection_par_time_ms + _cur_clear_ct_time_ms; + } else { + other_time_ms -= + update_rs_time + + ext_root_scan_time + mark_stack_scan_time + + scan_rs_time + obj_copy_time; } if (PrintGCDetails) { - gclog_or_tty->print_cr("%s%s, %1.8lf secs]", - abandoned ? " (abandoned)" : "", + gclog_or_tty->print_cr("%s, %1.8lf secs]", (last_pause_included_initial_mark) ? " (initial-mark)" : "", elapsed_ms / 1000.0); - if (!abandoned) { - if (_satb_drain_time_set) { - print_stats(1, "SATB Drain Time", _cur_satb_drain_time_ms); - } - if (_last_satb_drain_processed_buffers >= 0) { - print_stats(2, "Processed Buffers", _last_satb_drain_processed_buffers); - } - if (parallel) { - print_stats(1, "Parallel Time", _cur_collection_par_time_ms); - print_par_stats(2, "GC Worker Start Time", - _par_last_gc_worker_start_times_ms, false); - print_par_stats(2, "Update RS", _par_last_update_rs_times_ms); - print_par_sizes(3, "Processed Buffers", - _par_last_update_rs_processed_buffers, true); - print_par_stats(2, "Ext Root Scanning", - _par_last_ext_root_scan_times_ms); - print_par_stats(2, "Mark Stack Scanning", - _par_last_mark_stack_scan_times_ms); - print_par_stats(2, "Scan RS", _par_last_scan_rs_times_ms); - print_par_stats(2, "Object Copy", _par_last_obj_copy_times_ms); - print_par_stats(2, "Termination", _par_last_termination_times_ms); - print_par_sizes(3, "Termination Attempts", - _par_last_termination_attempts, true); - print_par_stats(2, "GC Worker End Time", - _par_last_gc_worker_end_times_ms, false); - print_stats(2, "Other", parallel_other_time); - print_stats(1, "Clear CT", _cur_clear_ct_time_ms); - } else { - print_stats(1, "Update RS", update_rs_time); - print_stats(2, "Processed Buffers", - (int)update_rs_processed_buffers); - print_stats(1, "Ext Root Scanning", ext_root_scan_time); - print_stats(1, "Mark Stack Scanning", mark_stack_scan_time); - print_stats(1, "Scan RS", scan_rs_time); - print_stats(1, "Object Copying", obj_copy_time); - } + if (_satb_drain_time_set) { + print_stats(1, "SATB Drain Time", _cur_satb_drain_time_ms); + } + if (_last_satb_drain_processed_buffers >= 0) { + print_stats(2, "Processed Buffers", _last_satb_drain_processed_buffers); + } + if (parallel) { + print_stats(1, "Parallel Time", _cur_collection_par_time_ms); + print_par_stats(2, "GC Worker Start Time", + _par_last_gc_worker_start_times_ms, false); + print_par_stats(2, "Update RS", _par_last_update_rs_times_ms); + print_par_sizes(3, "Processed Buffers", + _par_last_update_rs_processed_buffers, true); + print_par_stats(2, "Ext Root Scanning", + _par_last_ext_root_scan_times_ms); + print_par_stats(2, "Mark Stack Scanning", + _par_last_mark_stack_scan_times_ms); + print_par_stats(2, "Scan RS", _par_last_scan_rs_times_ms); + print_par_stats(2, "Object Copy", _par_last_obj_copy_times_ms); + print_par_stats(2, "Termination", _par_last_termination_times_ms); + print_par_sizes(3, "Termination Attempts", + _par_last_termination_attempts, true); + print_par_stats(2, "GC Worker End Time", + _par_last_gc_worker_end_times_ms, false); + print_stats(2, "Other", parallel_other_time); + print_stats(1, "Clear CT", _cur_clear_ct_time_ms); + } else { + print_stats(1, "Update RS", update_rs_time); + print_stats(2, "Processed Buffers", + (int)update_rs_processed_buffers); + print_stats(1, "Ext Root Scanning", ext_root_scan_time); + print_stats(1, "Mark Stack Scanning", mark_stack_scan_time); + print_stats(1, "Scan RS", scan_rs_time); + print_stats(1, "Object Copying", obj_copy_time); } #ifndef PRODUCT print_stats(1, "Cur Clear CC", _cur_clear_cc_time_ms); @@ -2159,7 +2148,7 @@ void G1CollectorPolicy::print_summary(PauseSummary* summary) const { body_summary->get_termination_seq() }; NumberSeq calc_other_times_ms(body_summary->get_parallel_seq(), - 7, other_parts); + 6, other_parts); check_other_times(2, body_summary->get_parallel_other_seq(), &calc_other_times_ms); } @@ -2177,9 +2166,8 @@ void G1CollectorPolicy::print_summary(PauseSummary* summary) const { } print_summary(1, "Other", summary->get_other_seq()); { - NumberSeq calc_other_times_ms; if (body_summary != NULL) { - // not abandoned + NumberSeq calc_other_times_ms; if (parallel) { // parallel NumberSeq* other_parts[] = { @@ -2188,7 +2176,7 @@ void G1CollectorPolicy::print_summary(PauseSummary* summary) const { body_summary->get_clear_ct_seq() }; calc_other_times_ms = NumberSeq(summary->get_total_seq(), - 3, other_parts); + 3, other_parts); } else { // serial NumberSeq* other_parts[] = { @@ -2200,13 +2188,10 @@ void G1CollectorPolicy::print_summary(PauseSummary* summary) const { body_summary->get_obj_copy_seq() }; calc_other_times_ms = NumberSeq(summary->get_total_seq(), - 7, other_parts); + 6, other_parts); } - } else { - // abandoned - calc_other_times_ms = NumberSeq(); + check_other_times(1, summary->get_other_seq(), &calc_other_times_ms); } - check_other_times(1, summary->get_other_seq(), &calc_other_times_ms); } } else { print_indent(0); @@ -2215,20 +2200,6 @@ void G1CollectorPolicy::print_summary(PauseSummary* summary) const { gclog_or_tty->print_cr(""); } -void -G1CollectorPolicy::print_abandoned_summary(PauseSummary* summary) const { - bool printed = false; - if (summary->get_total_seq()->num() > 0) { - printed = true; - print_summary(summary); - } - if (!printed) { - print_indent(0); - gclog_or_tty->print_cr("none"); - gclog_or_tty->print_cr(""); - } -} - void G1CollectorPolicy::print_tracing_info() const { if (TraceGen0Time) { gclog_or_tty->print_cr("ALL PAUSES"); @@ -2242,9 +2213,6 @@ void G1CollectorPolicy::print_tracing_info() const { gclog_or_tty->print_cr("EVACUATION PAUSES"); print_summary(_summary); - gclog_or_tty->print_cr("ABANDONED PAUSES"); - print_abandoned_summary(_abandoned_summary); - gclog_or_tty->print_cr("MISC"); print_summary_sd(0, "Stop World", _all_stop_world_times_ms); print_summary_sd(0, "Yields", _all_yield_times_ms); @@ -2870,19 +2838,12 @@ void G1CollectorPolicy::print_collection_set(HeapRegion* list_head, outputStream } #endif // !PRODUCT -bool +void G1CollectorPolicy_BestRegionsFirst::choose_collection_set( double target_pause_time_ms) { // Set this here - in case we're not doing young collections. double non_young_start_time_sec = os::elapsedTime(); - // The result that this routine will return. This will be set to - // false if: - // * we're doing a young or partially young collection and we - // have added the youg regions to collection set, or - // * we add old regions to the collection set. - bool abandon_collection = true; - start_recording_regions(); guarantee(target_pause_time_ms > 0.0, @@ -2986,10 +2947,6 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set( } assert(_inc_cset_size == _g1->young_list()->length(), "Invariant"); - if (_inc_cset_size > 0) { - assert(_collection_set != NULL, "Invariant"); - abandon_collection = false; - } double young_end_time_sec = os::elapsedTime(); _recorded_young_cset_choice_time_ms = @@ -3011,10 +2968,6 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set( NumberSeq seq; double avg_prediction = 100000000000000000.0; // something very large - // Save the current size of the collection set to detect - // if we actually added any old regions. - size_t n_young_regions = _collection_set_size; - do { hr = _collectionSetChooser->getNextMarkedRegion(time_remaining_ms, avg_prediction); @@ -3041,12 +2994,6 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set( if (!adaptive_young_list_length() && _collection_set_size < _young_list_fixed_length) _should_revert_to_full_young_gcs = true; - - if (_collection_set_size > n_young_regions) { - // We actually added old regions to the collection set - // so we are not abandoning this collection. - abandon_collection = false; - } } choose_collection_set_end: @@ -3059,19 +3006,6 @@ choose_collection_set_end: double non_young_end_time_sec = os::elapsedTime(); _recorded_non_young_cset_choice_time_ms = (non_young_end_time_sec - non_young_start_time_sec) * 1000.0; - - // Here we are supposed to return whether the pause should be - // abandoned or not (i.e., whether the collection set is empty or - // not). However, this introduces a subtle issue when a pause is - // initiated explicitly with System.gc() and - // +ExplicitGCInvokesConcurrent (see Comment #2 in CR 6944166), it's - // supposed to start a marking cycle, and it's abandoned. So, by - // returning false here we are telling the caller never to consider - // a pause to be abandoned. We'll actually remove all the code - // associated with abandoned pauses as part of CR 6963209, but we are - // just disabling them this way for the moment to avoid increasing - // further the amount of changes for CR 6944166. - return false; } void G1CollectorPolicy_BestRegionsFirst::record_full_collection_end() { @@ -3086,7 +3020,7 @@ expand_if_possible(size_t numRegions) { } void G1CollectorPolicy_BestRegionsFirst:: -record_collection_pause_end(bool abandoned) { - G1CollectorPolicy::record_collection_pause_end(abandoned); +record_collection_pause_end() { + G1CollectorPolicy::record_collection_pause_end(); assert(assertMarkedBytesDataOK(), "Marked regions not OK at pause end."); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp index 61dbee6c09e..33ee6ebc446 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @@ -63,8 +63,6 @@ class MainBodySummary: public CHeapObj { define_num_seq(mark_stack_scan) define_num_seq(update_rs) define_num_seq(scan_rs) - define_num_seq(scan_new_refs) // Only for temp use; added to - // in parallel case. define_num_seq(obj_copy) define_num_seq(termination) // parallel only define_num_seq(parallel_other) // parallel only @@ -78,9 +76,6 @@ public: virtual MainBodySummary* main_body_summary() { return this; } }; -class AbandonedSummary: public PauseSummary { -}; - class G1CollectorPolicy: public CollectorPolicy { protected: // The number of pauses during the execution. @@ -150,7 +145,6 @@ protected: TruncatedSeq* _concurrent_mark_cleanup_times_ms; Summary* _summary; - AbandonedSummary* _abandoned_summary; NumberSeq* _all_pause_times_ms; NumberSeq* _all_full_gc_times_ms; @@ -177,7 +171,6 @@ protected: double* _par_last_update_rs_times_ms; double* _par_last_update_rs_processed_buffers; double* _par_last_scan_rs_times_ms; - double* _par_last_scan_new_refs_times_ms; double* _par_last_obj_copy_times_ms; double* _par_last_termination_times_ms; double* _par_last_termination_attempts; @@ -576,7 +569,6 @@ protected: NumberSeq* calc_other_times_ms) const; void print_summary (PauseSummary* stats) const; - void print_abandoned_summary(PauseSummary* summary) const; void print_summary (int level, const char* str, NumberSeq* seq) const; void print_summary_sd (int level, const char* str, NumberSeq* seq) const; @@ -889,7 +881,7 @@ public: virtual void record_collection_pause_end_CH_strong_roots(); virtual void record_collection_pause_end_G1_strong_roots(); - virtual void record_collection_pause_end(bool abandoned); + virtual void record_collection_pause_end(); // Record the fact that a full collection occurred. virtual void record_full_collection_start(); @@ -933,14 +925,6 @@ public: _par_last_scan_rs_times_ms[thread] = ms; } - void record_scan_new_refs_time(int thread, double ms) { - _par_last_scan_new_refs_times_ms[thread] = ms; - } - - double get_scan_new_refs_time(int thread) { - return _par_last_scan_new_refs_times_ms[thread]; - } - void reset_obj_copy_time(int thread) { _par_last_obj_copy_times_ms[thread] = 0.0; } @@ -1010,7 +994,7 @@ public: // Choose a new collection set. Marks the chosen regions as being // "in_collection_set", and links them together. The head and number of // the collection set are available via access methods. - virtual bool choose_collection_set(double target_pause_time_ms) = 0; + virtual void choose_collection_set(double target_pause_time_ms) = 0; // The head of the list (via "next_in_collection_set()") representing the // current collection set. @@ -1267,7 +1251,7 @@ class G1CollectorPolicy_BestRegionsFirst: public G1CollectorPolicy { // If the estimated is less then desirable, resize if possible. void expand_if_possible(size_t numRegions); - virtual bool choose_collection_set(double target_pause_time_ms); + virtual void choose_collection_set(double target_pause_time_ms); virtual void record_collection_pause_start(double start_time_sec, size_t start_used); virtual void record_concurrent_mark_cleanup_end(size_t freed_bytes, @@ -1278,7 +1262,7 @@ public: G1CollectorPolicy_BestRegionsFirst() { _collectionSetChooser = new CollectionSetChooser(); } - void record_collection_pause_end(bool abandoned); + void record_collection_pause_end(); bool should_do_collection_pause(size_t word_size); // This is not needed any more, after the CSet choosing code was // changed to use the pause prediction work. But let's leave the diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp index 1037b83bd48..28ec22b04f3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,8 @@ template inline void FilterIntoCSClosure::do_oop_nv(T* p) { _g1->obj_in_cs(oopDesc::decode_heap_oop_not_null(heap_oop))) { _oc->do_oop(p); #if FILTERINTOCSCLOSURE_DOHISTOGRAMCOUNT - _dcto_cl->incr_count(); + if (_dcto_cl != NULL) + _dcto_cl->incr_count(); #endif } } @@ -113,7 +114,10 @@ template inline void G1ParPushHeapRSClosure::do_oop_nv(T* p) { if (_g1->in_cset_fast_test(obj)) { Prefetch::write(obj->mark_addr(), 0); Prefetch::read(obj->mark_addr(), (HeapWordSize*2)); + + // Place on the references queue _par_scan_state->push_on_queue(p); } } } + diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index a3a77ed186b..19ec341f980 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -122,23 +122,24 @@ public: HRInto_G1RemSet::HRInto_G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs) : G1RemSet(g1), _ct_bs(ct_bs), _g1p(_g1->g1_policy()), _cg1r(g1->concurrent_g1_refine()), - _par_traversal_in_progress(false), _new_refs(NULL), + _traversal_in_progress(false), + _cset_rs_update_cl(NULL), _cards_scanned(NULL), _total_cards_scanned(0) { _seq_task = new SubTasksDone(NumSeqTasks); guarantee(n_workers() > 0, "There should be some workers"); - _new_refs = NEW_C_HEAP_ARRAY(GrowableArray*, n_workers()); + _cset_rs_update_cl = NEW_C_HEAP_ARRAY(OopsInHeapRegionClosure*, n_workers()); for (uint i = 0; i < n_workers(); i++) { - _new_refs[i] = new (ResourceObj::C_HEAP) GrowableArray(8192,true); + _cset_rs_update_cl[i] = NULL; } } HRInto_G1RemSet::~HRInto_G1RemSet() { delete _seq_task; for (uint i = 0; i < n_workers(); i++) { - delete _new_refs[i]; + assert(_cset_rs_update_cl[i] == NULL, "it should be"); } - FREE_C_HEAP_ARRAY(GrowableArray*, _new_refs); + FREE_C_HEAP_ARRAY(OopsInHeapRegionClosure*, _cset_rs_update_cl); } void CountNonCleanMemRegionClosure::do_MemRegion(MemRegion mr) { @@ -306,12 +307,45 @@ void HRInto_G1RemSet::scanRS(OopsInHeapRegionClosure* oc, int worker_i) { _g1p->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0); } -void HRInto_G1RemSet::updateRS(int worker_i) { - ConcurrentG1Refine* cg1r = _g1->concurrent_g1_refine(); +// Closure used for updating RSets and recording references that +// point into the collection set. Only called during an +// evacuation pause. +class RefineRecordRefsIntoCSCardTableEntryClosure: public CardTableEntryClosure { + G1RemSet* _g1rs; + DirtyCardQueue* _into_cset_dcq; +public: + RefineRecordRefsIntoCSCardTableEntryClosure(G1CollectedHeap* g1h, + DirtyCardQueue* into_cset_dcq) : + _g1rs(g1h->g1_rem_set()), _into_cset_dcq(into_cset_dcq) + {} + bool do_card_ptr(jbyte* card_ptr, int worker_i) { + // The only time we care about recording cards that + // contain references that point into the collection set + // is during RSet updating within an evacuation pause. + // In this case worker_i should be the id of a GC worker thread. + assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); + assert(worker_i < (int) DirtyCardQueueSet::num_par_ids(), "should be a GC worker"); + + if (_g1rs->concurrentRefineOneCard(card_ptr, worker_i, true)) { + // 'card_ptr' contains references that point into the collection + // set. We need to record the card in the DCQS + // (G1CollectedHeap::into_cset_dirty_card_queue_set()) + // that's used for that purpose. + // + // Enqueue the card + _into_cset_dcq->enqueue(card_ptr); + } + return true; + } +}; + +void HRInto_G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, int worker_i) { double start = os::elapsedTime(); - // Apply the appropriate closure to all remaining log entries. - _g1->iterate_dirty_card_closure(false, worker_i); + // Apply the given closure to all remaining log entries. + RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq); + _g1->iterate_dirty_card_closure(&into_cset_update_rs_cl, into_cset_dcq, false, worker_i); + // Now there should be no dirty cards. if (G1RSLogCheckCardTable) { CountNonCleanMemRegionClosure cl(_g1); @@ -405,33 +439,6 @@ public: } }; -template void -HRInto_G1RemSet::scanNewRefsRS_work(OopsInHeapRegionClosure* oc, - int worker_i) { - double scan_new_refs_start_sec = os::elapsedTime(); - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - CardTableModRefBS* ct_bs = (CardTableModRefBS*) (g1h->barrier_set()); - for (int i = 0; i < _new_refs[worker_i]->length(); i++) { - T* p = (T*) _new_refs[worker_i]->at(i); - oop obj = oopDesc::load_decode_heap_oop(p); - // *p was in the collection set when p was pushed on "_new_refs", but - // another thread may have processed this location from an RS, so it - // might not point into the CS any longer. If so, it's obviously been - // processed, and we don't need to do anything further. - if (g1h->obj_in_cs(obj)) { - HeapRegion* r = g1h->heap_region_containing(p); - - DEBUG_ONLY(HeapRegion* to = g1h->heap_region_containing(obj)); - oc->set_region(r); - // If "p" has already been processed concurrently, this is - // idempotent. - oc->do_oop(p); - } - } - double scan_new_refs_time_ms = (os::elapsedTime() - scan_new_refs_start_sec) * 1000.0; - _g1p->record_scan_new_refs_time(worker_i, scan_new_refs_time_ms); -} - void HRInto_G1RemSet::cleanupHRRS() { HeapRegionRemSet::cleanup(); } @@ -457,32 +464,48 @@ HRInto_G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, count_cl.print_histo(); } - if (ParallelGCThreads > 0) { - // The two flags below were introduced temporarily to serialize - // the updating and scanning of remembered sets. There are some - // race conditions when these two operations are done in parallel - // and they are causing failures. When we resolve said race - // conditions, we'll revert back to parallel remembered set - // updating and scanning. See CRs 6677707 and 6677708. - if (G1UseParallelRSetUpdating || (worker_i == 0)) { - updateRS(worker_i); - scanNewRefsRS(oc, worker_i); - } else { - _g1p->record_update_rs_processed_buffers(worker_i, 0.0); - _g1p->record_update_rs_time(worker_i, 0.0); - _g1p->record_scan_new_refs_time(worker_i, 0.0); - } - if (G1UseParallelRSetScanning || (worker_i == 0)) { - scanRS(oc, worker_i); - } else { - _g1p->record_scan_rs_time(worker_i, 0.0); - } + // We cache the value of 'oc' closure into the appropriate slot in the + // _cset_rs_update_cl for this worker + assert(worker_i < (int)n_workers(), "sanity"); + _cset_rs_update_cl[worker_i] = oc; + + // A DirtyCardQueue that is used to hold cards containing references + // that point into the collection set. This DCQ is associated with a + // special DirtyCardQueueSet (see g1CollectedHeap.hpp). Under normal + // circumstances (i.e. the pause successfully completes), these cards + // are just discarded (there's no need to update the RSets of regions + // that were in the collection set - after the pause these regions + // are wholly 'free' of live objects. In the event of an evacuation + // failure the cards/buffers in this queue set are: + // * passed to the DirtyCardQueueSet that is used to manage deferred + // RSet updates, or + // * scanned for references that point into the collection set + // and the RSet of the corresponding region in the collection set + // is updated immediately. + DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set()); + + assert((ParallelGCThreads > 0) || worker_i == 0, "invariant"); + + // The two flags below were introduced temporarily to serialize + // the updating and scanning of remembered sets. There are some + // race conditions when these two operations are done in parallel + // and they are causing failures. When we resolve said race + // conditions, we'll revert back to parallel remembered set + // updating and scanning. See CRs 6677707 and 6677708. + if (G1UseParallelRSetUpdating || (worker_i == 0)) { + updateRS(&into_cset_dcq, worker_i); } else { - assert(worker_i == 0, "invariant"); - updateRS(0); - scanNewRefsRS(oc, 0); - scanRS(oc, 0); + _g1p->record_update_rs_processed_buffers(worker_i, 0.0); + _g1p->record_update_rs_time(worker_i, 0.0); } + if (G1UseParallelRSetScanning || (worker_i == 0)) { + scanRS(oc, worker_i); + } else { + _g1p->record_scan_rs_time(worker_i, 0.0); + } + + // We now clear the cached values of _cset_rs_update_cl for this worker + _cset_rs_update_cl[worker_i] = NULL; } void HRInto_G1RemSet:: @@ -497,9 +520,9 @@ prepare_for_oops_into_collection_set_do() { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); dcqs.concatenate_logs(); - assert(!_par_traversal_in_progress, "Invariant between iterations."); + assert(!_traversal_in_progress, "Invariant between iterations."); + set_traversal(true); if (ParallelGCThreads > 0) { - set_par_traversal(true); _seq_task->set_par_threads((int)n_workers()); } guarantee( _cards_scanned == NULL, "invariant" ); @@ -519,49 +542,65 @@ class cleanUpIteratorsClosure : public HeapRegionClosure { } }; -class UpdateRSetOopsIntoCSImmediate : public OopClosure { - G1CollectedHeap* _g1; -public: - UpdateRSetOopsIntoCSImmediate(G1CollectedHeap* g1) : _g1(g1) { } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - template void do_oop_work(T* p) { - HeapRegion* to = _g1->heap_region_containing(oopDesc::load_decode_heap_oop(p)); - if (to->in_collection_set()) { - to->rem_set()->add_reference(p, 0); - } - } -}; - -class UpdateRSetOopsIntoCSDeferred : public OopClosure { +// This closure, applied to a DirtyCardQueueSet, is used to immediately +// update the RSets for the regions in the CSet. For each card it iterates +// through the oops which coincide with that card. It scans the reference +// fields in each oop; when it finds an oop that points into the collection +// set, the RSet for the region containing the referenced object is updated. +// Note: _par_traversal_in_progress in the G1RemSet must be FALSE; otherwise +// the UpdateRSetImmediate closure will cause cards to be enqueued on to +// the DCQS that we're iterating over, causing an infinite loop. +class UpdateRSetCardTableEntryIntoCSetClosure: public CardTableEntryClosure { G1CollectedHeap* _g1; CardTableModRefBS* _ct_bs; - DirtyCardQueue* _dcq; public: - UpdateRSetOopsIntoCSDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) : - _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) { } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - template void do_oop_work(T* p) { - oop obj = oopDesc::load_decode_heap_oop(p); - if (_g1->obj_in_cs(obj)) { - size_t card_index = _ct_bs->index_for(p); - if (_ct_bs->mark_card_deferred(card_index)) { - _dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index)); - } - } + UpdateRSetCardTableEntryIntoCSetClosure(G1CollectedHeap* g1, + CardTableModRefBS* bs): + _g1(g1), _ct_bs(bs) + { } + + bool do_card_ptr(jbyte* card_ptr, int worker_i) { + // Construct the region representing the card. + HeapWord* start = _ct_bs->addr_for(card_ptr); + // And find the region containing it. + HeapRegion* r = _g1->heap_region_containing(start); + assert(r != NULL, "unexpected null"); + + // Scan oops in the card looking for references into the collection set + HeapWord* end = _ct_bs->addr_for(card_ptr + 1); + MemRegion scanRegion(start, end); + + UpdateRSetImmediate update_rs_cl(_g1->g1_rem_set()); + FilterIntoCSClosure update_rs_cset_oop_cl(NULL, _g1, &update_rs_cl); + FilterOutOfRegionClosure filter_then_update_rs_cset_oop_cl(r, &update_rs_cset_oop_cl); + + // We can pass false as the "filter_young" parameter here as: + // * we should be in a STW pause, + // * the DCQS to which this closure is applied is used to hold + // references that point into the collection set from the prior + // RSet updating, + // * the post-write barrier shouldn't be logging updates to young + // regions (but there is a situation where this can happen - see + // the comment in HRInto_G1RemSet::concurrentRefineOneCard below - + // that should not be applicable here), and + // * during actual RSet updating, the filtering of cards in young + // regions in HeapRegion::oops_on_card_seq_iterate_careful is + // employed. + // As a result, when this closure is applied to "refs into cset" + // DCQS, we shouldn't see any cards in young regions. + update_rs_cl.set_region(r); + HeapWord* stop_point = + r->oops_on_card_seq_iterate_careful(scanRegion, + &filter_then_update_rs_cset_oop_cl, + false /* filter_young */); + + // Since this is performed in the event of an evacuation failure, we + // we shouldn't see a non-null stop point + assert(stop_point == NULL, "saw an unallocated region"); + return true; } }; -template void HRInto_G1RemSet::new_refs_iterate_work(OopClosure* cl) { - for (size_t i = 0; i < n_workers(); i++) { - for (int j = 0; j < _new_refs[i]->length(); j++) { - T* p = (T*) _new_refs[i]->at(j); - cl->do_oop(p); - } - } -} - void HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do() { guarantee( _cards_scanned != NULL, "invariant" ); _total_cards_scanned = 0; @@ -580,27 +619,42 @@ void HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do() { // Set all cards back to clean. _g1->cleanUpCardTable(); - if (ParallelGCThreads > 0) { - set_par_traversal(false); - } + set_traversal(false); + + DirtyCardQueueSet& into_cset_dcqs = _g1->into_cset_dirty_card_queue_set(); + int into_cset_n_buffers = into_cset_dcqs.completed_buffers_num(); if (_g1->evacuation_failed()) { - // Restore remembered sets for the regions pointing into - // the collection set. + // Restore remembered sets for the regions pointing into the collection set. + if (G1DeferredRSUpdate) { - DirtyCardQueue dcq(&_g1->dirty_card_queue_set()); - UpdateRSetOopsIntoCSDeferred deferred_update(_g1, &dcq); - new_refs_iterate(&deferred_update); + // If deferred RS updates are enabled then we just need to transfer + // the completed buffers from (a) the DirtyCardQueueSet used to hold + // cards that contain references that point into the collection set + // to (b) the DCQS used to hold the deferred RS updates + _g1->dirty_card_queue_set().merge_bufferlists(&into_cset_dcqs); } else { - UpdateRSetOopsIntoCSImmediate immediate_update(_g1); - new_refs_iterate(&immediate_update); + + CardTableModRefBS* bs = (CardTableModRefBS*)_g1->barrier_set(); + UpdateRSetCardTableEntryIntoCSetClosure update_rs_cset_immediate(_g1, bs); + + int n_completed_buffers = 0; + while (into_cset_dcqs.apply_closure_to_completed_buffer(&update_rs_cset_immediate, + 0, 0, true)) { + n_completed_buffers++; + } + assert(n_completed_buffers == into_cset_n_buffers, "missed some buffers"); } } - for (uint i = 0; i < n_workers(); i++) { - _new_refs[i]->clear(); - } - assert(!_par_traversal_in_progress, "Invariant between iterations."); + // Free any completed buffers in the DirtyCardQueueSet used to hold cards + // which contain references that point into the collection. + _g1->into_cset_dirty_card_queue_set().clear(); + assert(_g1->into_cset_dirty_card_queue_set().completed_buffers_num() == 0, + "all buffers should be freed"); + _g1->into_cset_dirty_card_queue_set().clear_n_completed_buffers(); + + assert(!_traversal_in_progress, "Invariant between iterations."); } class UpdateRSObjectClosure: public ObjectClosure { @@ -652,7 +706,43 @@ void HRInto_G1RemSet::scrub_par(BitMap* region_bm, BitMap* card_bm, static IntHistogram out_of_histo(50, 50); -void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i) { +class TriggerClosure : public OopClosure { + bool _trigger; +public: + TriggerClosure() : _trigger(false) { } + bool value() const { return _trigger; } + template void do_oop_nv(T* p) { _trigger = true; } + virtual void do_oop(oop* p) { do_oop_nv(p); } + virtual void do_oop(narrowOop* p) { do_oop_nv(p); } +}; + +class InvokeIfNotTriggeredClosure: public OopClosure { + TriggerClosure* _t; + OopClosure* _oc; +public: + InvokeIfNotTriggeredClosure(TriggerClosure* t, OopClosure* oc): + _t(t), _oc(oc) { } + template void do_oop_nv(T* p) { + if (!_t->value()) _oc->do_oop(p); + } + virtual void do_oop(oop* p) { do_oop_nv(p); } + virtual void do_oop(narrowOop* p) { do_oop_nv(p); } +}; + +class Mux2Closure : public OopClosure { + OopClosure* _c1; + OopClosure* _c2; +public: + Mux2Closure(OopClosure *c1, OopClosure *c2) : _c1(c1), _c2(c2) { } + template void do_oop_nv(T* p) { + _c1->do_oop(p); _c2->do_oop(p); + } + virtual void do_oop(oop* p) { do_oop_nv(p); } + virtual void do_oop(narrowOop* p) { do_oop_nv(p); } +}; + +bool HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i, + bool check_for_refs_into_cset) { // Construct the region representing the card. HeapWord* start = _ct_bs->addr_for(card_ptr); // And find the region containing it. @@ -669,7 +759,16 @@ void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i UpdateRSOopClosure update_rs_oop_cl(this, worker_i); update_rs_oop_cl.set_from(r); - FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, &update_rs_oop_cl); + + TriggerClosure trigger_cl; + FilterIntoCSClosure into_cs_cl(NULL, _g1, &trigger_cl); + InvokeIfNotTriggeredClosure invoke_cl(&trigger_cl, &into_cs_cl); + Mux2Closure mux(&invoke_cl, &update_rs_oop_cl); + + FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, + (check_for_refs_into_cset ? + (OopClosure*)&mux : + (OopClosure*)&update_rs_oop_cl)); // Undirty the card. *card_ptr = CardTableModRefBS::clean_card_val(); @@ -717,11 +816,18 @@ void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i out_of_histo.add_entry(filter_then_update_rs_oop_cl.out_of_region()); _conc_refine_cards++; } + + return trigger_cl.value(); } -void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { +bool HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i, + bool check_for_refs_into_cset) { // If the card is no longer dirty, nothing to do. - if (*card_ptr != CardTableModRefBS::dirty_card_val()) return; + if (*card_ptr != CardTableModRefBS::dirty_card_val()) { + // No need to return that this card contains refs that point + // into the collection set. + return false; + } // Construct the region representing the card. HeapWord* start = _ct_bs->addr_for(card_ptr); @@ -729,7 +835,9 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { HeapRegion* r = _g1->heap_region_containing(start); if (r == NULL) { guarantee(_g1->is_in_permanent(start), "Or else where?"); - return; // Not in the G1 heap (might be in perm, for example.) + // Again no need to return that this card contains refs that + // point into the collection set. + return false; // Not in the G1 heap (might be in perm, for example.) } // Why do we have to check here whether a card is on a young region, // given that we dirty young regions and, as a result, the @@ -743,7 +851,7 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { // and it doesn't happen often, but it can happen. So, the extra // check below filters out those cards. if (r->is_young()) { - return; + return false; } // While we are processing RSet buffers during the collection, we // actually don't want to scan any cards on the collection set, @@ -756,7 +864,7 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { // however, that if evacuation fails, we have to scan any objects // that were not moved and create any missing entries. if (r->in_collection_set()) { - return; + return false; } // Should we defer processing the card? @@ -797,8 +905,14 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { // cache. // Immediately process res; no need to process card_ptr. + jbyte* res = card_ptr; bool defer = false; + + // This gets set to true if the card being refined has references + // that point into the collection set. + bool oops_into_cset = false; + if (_cg1r->use_cache()) { jbyte* res = _cg1r->cache_insert(card_ptr, &defer); if (res != NULL && (res != card_ptr || defer)) { @@ -815,14 +929,31 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { // Process card pointer we get back from the hot card cache. This // will check whether the region containing the card is young // _after_ checking that the region has been allocated from. - concurrentRefineOneCard_impl(res, worker_i); + oops_into_cset = concurrentRefineOneCard_impl(res, worker_i, + false /* check_for_refs_into_cset */); + // The above call to concurrentRefineOneCard_impl is only + // performed if the hot card cache is enabled. This cache is + // disabled during an evacuation pause - which is the only + // time when we need know if the card contains references + // that point into the collection set. Also when the hot card + // cache is enabled, this code is executed by the concurrent + // refine threads - rather than the GC worker threads - and + // concurrentRefineOneCard_impl will return false. + assert(!oops_into_cset, "should not see true here"); } } } if (!defer) { - concurrentRefineOneCard_impl(card_ptr, worker_i); + oops_into_cset = + concurrentRefineOneCard_impl(card_ptr, worker_i, check_for_refs_into_cset); + // We should only be detecting that the card contains references + // that point into the collection set if the current thread is + // a GC worker thread. + assert(!oops_into_cset || SafepointSynchronize::is_at_safepoint(), + "invalid result at non safepoint"); } + return oops_into_cset; } class HRRSStatsIter: public HeapRegionClosure { @@ -920,6 +1051,7 @@ void HRInto_G1RemSet::print_summary_info() { } } + void HRInto_G1RemSet::prepare_for_verify() { if (G1HRRSFlushLogBuffersOnVerify && (VerifyBeforeGC || VerifyAfterGC) @@ -932,7 +1064,9 @@ void HRInto_G1RemSet::prepare_for_verify() { } bool cg1r_use_cache = _cg1r->use_cache(); _cg1r->set_use_cache(false); - updateRS(0); + DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set()); + updateRS(&into_cset_dcq, 0); + _g1->into_cset_dirty_card_queue_set().clear(); _cg1r->set_use_cache(cg1r_use_cache); assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp index bc30a9699c4..fcb5ecd76cf 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,7 +83,13 @@ public: // Refine the card corresponding to "card_ptr". If "sts" is non-NULL, // join and leave around parts that must be atomic wrt GC. (NULL means // being done at a safepoint.) - virtual void concurrentRefineOneCard(jbyte* card_ptr, int worker_i) {} + // With some implementations of this routine, when check_for_refs_into_cset + // is true, a true result may be returned if the given card contains oops + // that have references into the current collection set. + virtual bool concurrentRefineOneCard(jbyte* card_ptr, int worker_i, + bool check_for_refs_into_cset) { + return false; + } // Print any relevant summary info. virtual void print_summary_info() {} @@ -142,24 +148,22 @@ protected: size_t* _cards_scanned; size_t _total_cards_scanned; - // _par_traversal_in_progress is "true" iff a parallel traversal is in - // progress. If so, then cards added to remembered sets should also have - // their references into the collection summarized in "_new_refs". - bool _par_traversal_in_progress; - void set_par_traversal(bool b) { _par_traversal_in_progress = b; } - GrowableArray** _new_refs; - template void new_refs_iterate_work(OopClosure* cl); - void new_refs_iterate(OopClosure* cl) { - if (UseCompressedOops) { - new_refs_iterate_work(cl); - } else { - new_refs_iterate_work(cl); - } - } + // _traversal_in_progress is "true" iff a traversal is in progress. + + bool _traversal_in_progress; + void set_traversal(bool b) { _traversal_in_progress = b; } + + // Used for caching the closure that is responsible for scanning + // references into the collection set. + OopsInHeapRegionClosure** _cset_rs_update_cl; // The routine that performs the actual work of refining a dirty // card. - void concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i); + // If check_for_refs_into_refs is true then a true result is returned + // if the card contains oops that have references into the current + // collection set. + bool concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i, + bool check_for_refs_into_cset); protected: template void write_ref_nv(HeapRegion* from, T* p); @@ -188,7 +192,7 @@ public: scanNewRefsRS_work(oc, worker_i); } } - void updateRS(int worker_i); + void updateRS(DirtyCardQueue* into_cset_dcq, int worker_i); HeapRegion* calculateStartRegion(int i); HRInto_G1RemSet* as_HRInto_G1RemSet() { return this; } @@ -219,7 +223,11 @@ public: void scrub_par(BitMap* region_bm, BitMap* card_bm, int worker_num, int claim_val); - virtual void concurrentRefineOneCard(jbyte* card_ptr, int worker_i); + // If check_for_refs_into_cset is true then a true result is returned + // if the card contains oops that have references into the current + // collection set. + virtual bool concurrentRefineOneCard(jbyte* card_ptr, int worker_i, + bool check_for_refs_into_cset); virtual void print_summary_info(); virtual void prepare_for_verify(); @@ -265,3 +273,16 @@ public: // bool idempotent() { return true; } bool apply_to_weak_ref_discovered_field() { return true; } }; + +class UpdateRSetImmediate: public OopsInHeapRegionClosure { +private: + G1RemSet* _g1_rem_set; + + template void do_oop_work(T* p); +public: + UpdateRSetImmediate(G1RemSet* rs) : + _g1_rem_set(rs) {} + + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop( oop* p) { do_oop_work(p); } +}; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp index 2b916f866d5..ce64065527b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,19 +56,25 @@ template inline void HRInto_G1RemSet::par_write_ref_nv(HeapRegion* fro assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); } #endif // ASSERT - assert(from == NULL || from->is_in_reserved(p), - "p is not in from"); + + assert(from == NULL || from->is_in_reserved(p), "p is not in from"); + HeapRegion* to = _g1->heap_region_containing(obj); // The test below could be optimized by applying a bit op to to and from. if (to != NULL && from != NULL && from != to) { - // There is a tricky infinite loop if we keep pushing - // self forwarding pointers onto our _new_refs list. - // The _par_traversal_in_progress flag is true during the collection pause, - // false during the evacuation failure handing. - if (_par_traversal_in_progress && + // The _traversal_in_progress flag is true during the collection pause, + // false during the evacuation failure handling. This should avoid a + // potential loop if we were to add the card containing 'p' to the DCQS + // that's used to regenerate the remembered sets for the collection set, + // in the event of an evacuation failure, here. The UpdateRSImmediate + // closure will eventally call this routine. + if (_traversal_in_progress && to->in_collection_set() && !self_forwarded(obj)) { - _new_refs[tid]->push((void*)p); - // Deferred updates to the Cset are either discarded (in the normal case), + + assert(_cset_rs_update_cl[tid] != NULL, "should have been set already"); + _cset_rs_update_cl[tid]->do_oop(p); + + // Deferred updates to the CSet are either discarded (in the normal case), // or processed (if an evacuation failure occurs) at the end // of the collection. // See HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do(). @@ -89,3 +95,12 @@ template inline void UpdateRSOopClosure::do_oop_work(T* p) { assert(_from != NULL, "from region must be non-NULL"); _rs->par_write_ref(_from, p, _worker_i); } + +template inline void UpdateRSetImmediate::do_oop_work(T* p) { + assert(_from->is_in_reserved(p), "paranoia"); + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop) && !_from->is_survivor()) { + _g1_rem_set->par_write_ref(_from, p, 0); + } +} + diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 4e5446e1f5e..58b55123aae 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -683,6 +683,8 @@ oops_on_card_seq_iterate_careful(MemRegion mr, return NULL; } + assert(!is_young(), "check value of filter_young"); + // We used to use "block_start_careful" here. But we're actually happy // to update the BOT while we do this... HeapWord* cur = block_start(mr.start()); @@ -788,8 +790,18 @@ void HeapRegion::verify(bool allow_dirty, int objs = 0; int blocks = 0; VerifyLiveClosure vl_cl(g1, use_prev_marking); + bool is_humongous = isHumongous(); + size_t object_num = 0; while (p < top()) { size_t size = oop(p)->size(); + if (is_humongous != g1->isHumongous(size)) { + gclog_or_tty->print_cr("obj "PTR_FORMAT" is of %shumongous size (" + SIZE_FORMAT" words) in a %shumongous region", + p, g1->isHumongous(size) ? "" : "non-", + size, is_humongous ? "" : "non-"); + *failures = true; + } + object_num += 1; if (blocks == BLOCK_SAMPLE_INTERVAL) { HeapWord* res = block_start_const(p + (size/2)); if (p != res) { @@ -855,6 +867,13 @@ void HeapRegion::verify(bool allow_dirty, } } + if (is_humongous && object_num > 1) { + gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is humongous " + "but has "SIZE_FORMAT", objects", + bottom(), end(), object_num); + *failures = true; + } + if (p != top()) { gclog_or_tty->print_cr("end of last object "PTR_FORMAT" " "does not match top "PTR_FORMAT, p, top()); diff --git a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp index 434836345c8..5bc3ab29c70 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp @@ -424,7 +424,7 @@ void SparsePRT::cleanup_all() { SparsePRT::SparsePRT(HeapRegion* hr) : - _expanded(false), _next_expanded(NULL) + _hr(hr), _expanded(false), _next_expanded(NULL) { _cur = new RSHashTable(InitialCapacity); _next = _cur; diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep b/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep index 7cda699d3ce..6efae46edd1 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep @@ -1,5 +1,5 @@ // -// Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,8 @@ binaryTreeDictionary.cpp spaceDecorator.hpp binaryTreeDictionary.hpp freeBlockDictionary.hpp binaryTreeDictionary.hpp freeList.hpp +blockOffsetTable.inline.hpp concurrentMarkSweepGeneration.hpp + cmsAdaptiveSizePolicy.cpp cmsAdaptiveSizePolicy.hpp cmsAdaptiveSizePolicy.cpp defNewGeneration.hpp cmsAdaptiveSizePolicy.cpp gcStats.hpp @@ -85,7 +87,7 @@ cmsOopClosures.hpp genOopClosures.hpp cmsOopClosures.inline.hpp cmsOopClosures.hpp cmsOopClosures.inline.hpp concurrentMarkSweepGeneration.hpp -cmsPermGen.cpp blockOffsetTable.hpp +cmsPermGen.cpp blockOffsetTable.inline.hpp cmsPermGen.cpp cSpaceCounters.hpp cmsPermGen.cpp cmsPermGen.hpp cmsPermGen.cpp collectedHeap.inline.hpp @@ -121,6 +123,7 @@ compactibleFreeListSpace.cpp universe.inline.hpp compactibleFreeListSpace.cpp vmThread.hpp compactibleFreeListSpace.hpp binaryTreeDictionary.hpp +compactibleFreeListSpace.hpp blockOffsetTable.inline.hpp compactibleFreeListSpace.hpp freeList.hpp compactibleFreeListSpace.hpp promotionInfo.hpp compactibleFreeListSpace.hpp space.hpp @@ -149,6 +152,7 @@ concurrentMarkSweepGeneration.cpp isGCActiveMark.hpp concurrentMarkSweepGeneration.cpp iterator.hpp concurrentMarkSweepGeneration.cpp java.hpp concurrentMarkSweepGeneration.cpp jvmtiExport.hpp +concurrentMarkSweepGeneration.cpp memoryService.hpp concurrentMarkSweepGeneration.cpp oop.inline.hpp concurrentMarkSweepGeneration.cpp parNewGeneration.hpp concurrentMarkSweepGeneration.cpp referencePolicy.hpp @@ -165,6 +169,7 @@ concurrentMarkSweepGeneration.hpp gSpaceCounters.hpp concurrentMarkSweepGeneration.hpp gcStats.hpp concurrentMarkSweepGeneration.hpp generation.hpp concurrentMarkSweepGeneration.hpp generationCounters.hpp +concurrentMarkSweepGeneration.hpp memoryService.hpp concurrentMarkSweepGeneration.hpp mutexLocker.hpp concurrentMarkSweepGeneration.hpp taskqueue.hpp concurrentMarkSweepGeneration.hpp virtualspace.hpp diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 index 13e3464ed8f..d1476972275 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 @@ -1,5 +1,5 @@ // -// Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -241,6 +241,7 @@ g1MMUTracker.cpp mutexLocker.hpp g1MMUTracker.hpp debug.hpp g1MMUTracker.hpp allocation.hpp + g1RemSet.cpp bufferingOopClosure.hpp g1RemSet.cpp concurrentG1Refine.hpp g1RemSet.cpp concurrentG1RefineThread.hpp diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge index e06ed445a0d..83eae5eebe7 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge @@ -330,7 +330,6 @@ psPromotionManager.cpp psPromotionManager.inline.hpp psPromotionManager.cpp psScavenge.inline.hpp psPromotionManager.hpp allocation.hpp -psPromotionManager.hpp prefetchQueue.hpp psPromotionManager.hpp psPromotionLAB.hpp psPromotionManager.hpp taskqueue.hpp diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp index dc655aed136..e31e2854664 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @@ -51,9 +51,14 @@ ParScanThreadState::ParScanThreadState(Space* to_space_, _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this), _keep_alive_closure(&_scan_weak_ref_closure), _promotion_failure_size(0), - _pushes(0), _pops(0), _steals(0), _steal_attempts(0), _term_attempts(0), _strong_roots_time(0.0), _term_time(0.0) { + #if TASKQUEUE_STATS + _term_attempts = 0; + _overflow_refills = 0; + _overflow_refill_objs = 0; + #endif // TASKQUEUE_STATS + _survivor_chunk_array = (ChunkArray*) old_gen()->get_data_recorder(thread_num()); _hash_seed = 17; // Might want to take time-based random value. @@ -100,7 +105,6 @@ void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) { // Push remainder. bool ok = work_queue()->push(old); assert(ok, "just popped, push must be okay"); - note_push(); } else { // Restore length so that it can be used if there // is a promotion failure and forwarding pointers @@ -126,7 +130,6 @@ void ParScanThreadState::trim_queues(int max_size) { while (queue->size() > (juint)max_size) { oop obj_to_scan; if (queue->pop_local(obj_to_scan)) { - note_pop(); if ((HeapWord *)obj_to_scan < young_old_boundary()) { if (obj_to_scan->is_objArray() && obj_to_scan->is_forwarded() && @@ -271,20 +274,28 @@ public: GrowableArray** overflow_stacks_, size_t desired_plab_sz, ParallelTaskTerminator& term); + + ~ParScanThreadStateSet() { TASKQUEUE_STATS_ONLY(reset_stats()); } + inline ParScanThreadState& thread_state(int i); - int pushes() { return _pushes; } - int pops() { return _pops; } - int steals() { return _steals; } + void reset(bool promotion_failed); void flush(); + + #if TASKQUEUE_STATS + static void + print_termination_stats_hdr(outputStream* const st = gclog_or_tty); + void print_termination_stats(outputStream* const st = gclog_or_tty); + static void + print_taskqueue_stats_hdr(outputStream* const st = gclog_or_tty); + void print_taskqueue_stats(outputStream* const st = gclog_or_tty); + void reset_stats(); + #endif // TASKQUEUE_STATS + private: ParallelTaskTerminator& _term; ParNewGeneration& _gen; Generation& _next_gen; - // staticstics - int _pushes; - int _pops; - int _steals; }; @@ -294,8 +305,7 @@ ParScanThreadStateSet::ParScanThreadStateSet( GrowableArray** overflow_stack_set_, size_t desired_plab_sz, ParallelTaskTerminator& term) : ResourceArray(sizeof(ParScanThreadState), num_threads), - _gen(gen), _next_gen(old_gen), _term(term), - _pushes(0), _pops(0), _steals(0) + _gen(gen), _next_gen(old_gen), _term(term) { assert(num_threads > 0, "sanity check!"); // Initialize states. @@ -323,6 +333,82 @@ void ParScanThreadStateSet::reset(bool promotion_failed) } } +#if TASKQUEUE_STATS +void +ParScanThreadState::reset_stats() +{ + taskqueue_stats().reset(); + _term_attempts = 0; + _overflow_refills = 0; + _overflow_refill_objs = 0; +} + +void ParScanThreadStateSet::reset_stats() +{ + for (int i = 0; i < length(); ++i) { + thread_state(i).reset_stats(); + } +} + +void +ParScanThreadStateSet::print_termination_stats_hdr(outputStream* const st) +{ + st->print_raw_cr("GC Termination Stats"); + st->print_raw_cr(" elapsed --strong roots-- " + "-------termination-------"); + st->print_raw_cr("thr ms ms % " + " ms % attempts"); + st->print_raw_cr("--- --------- --------- ------ " + "--------- ------ --------"); +} + +void ParScanThreadStateSet::print_termination_stats(outputStream* const st) +{ + print_termination_stats_hdr(st); + + for (int i = 0; i < length(); ++i) { + const ParScanThreadState & pss = thread_state(i); + const double elapsed_ms = pss.elapsed_time() * 1000.0; + const double s_roots_ms = pss.strong_roots_time() * 1000.0; + const double term_ms = pss.term_time() * 1000.0; + st->print_cr("%3d %9.2f %9.2f %6.2f " + "%9.2f %6.2f " SIZE_FORMAT_W(8), + i, elapsed_ms, s_roots_ms, s_roots_ms * 100 / elapsed_ms, + term_ms, term_ms * 100 / elapsed_ms, pss.term_attempts()); + } +} + +// Print stats related to work queue activity. +void ParScanThreadStateSet::print_taskqueue_stats_hdr(outputStream* const st) +{ + st->print_raw_cr("GC Task Stats"); + st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr(); + st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr(); +} + +void ParScanThreadStateSet::print_taskqueue_stats(outputStream* const st) +{ + print_taskqueue_stats_hdr(st); + + TaskQueueStats totals; + for (int i = 0; i < length(); ++i) { + const ParScanThreadState & pss = thread_state(i); + const TaskQueueStats & stats = pss.taskqueue_stats(); + st->print("%3d ", i); stats.print(st); st->cr(); + totals += stats; + + if (pss.overflow_refills() > 0) { + st->print_cr(" " SIZE_FORMAT_W(10) " overflow refills " + SIZE_FORMAT_W(10) " overflow objects", + pss.overflow_refills(), pss.overflow_refill_objs()); + } + } + st->print("tot "); totals.print(st); st->cr(); + + DEBUG_ONLY(totals.verify()); +} +#endif // TASKQUEUE_STATS + void ParScanThreadStateSet::flush() { // Work in this loop should be kept as lightweight as @@ -346,42 +432,8 @@ void ParScanThreadStateSet::flush() // Inform old gen that we're done. _next_gen.par_promote_alloc_done(i); _next_gen.par_oop_since_save_marks_iterate_done(i); - - // Flush stats related to work queue activity (push/pop/steal) - // This could conceivably become a bottleneck; if so, we'll put the - // stat's gathering under the flag. - if (PAR_STATS_ENABLED) { - _pushes += par_scan_state.pushes(); - _pops += par_scan_state.pops(); - _steals += par_scan_state.steals(); - if (ParallelGCVerbose) { - gclog_or_tty->print("Thread %d complete:\n" - " Pushes: %7d Pops: %7d Steals %7d (in %d attempts)\n", - i, par_scan_state.pushes(), par_scan_state.pops(), - par_scan_state.steals(), par_scan_state.steal_attempts()); - if (par_scan_state.overflow_pushes() > 0 || - par_scan_state.overflow_refills() > 0) { - gclog_or_tty->print(" Overflow pushes: %7d " - "Overflow refills: %7d for %d objs.\n", - par_scan_state.overflow_pushes(), - par_scan_state.overflow_refills(), - par_scan_state.overflow_refill_objs()); - } - - double elapsed = par_scan_state.elapsed(); - double strong_roots = par_scan_state.strong_roots_time(); - double term = par_scan_state.term_time(); - gclog_or_tty->print( - " Elapsed: %7.2f ms.\n" - " Strong roots: %7.2f ms (%6.2f%%)\n" - " Termination: %7.2f ms (%6.2f%%) (in %d entries)\n", - elapsed * 1000.0, - strong_roots * 1000.0, (strong_roots*100.0/elapsed), - term * 1000.0, (term*100.0/elapsed), - par_scan_state.term_attempts()); - } - } } + if (UseConcMarkSweepGC && ParallelGCThreads > 0) { // We need to call this even when ResizeOldPLAB is disabled // so as to avoid breaking some asserts. While we may be able @@ -456,15 +508,12 @@ void ParEvacuateFollowersClosure::do_void() { // We have no local work, attempt to steal from other threads. // attempt to steal work from promoted. - par_scan_state()->note_steal_attempt(); if (task_queues()->steal(par_scan_state()->thread_num(), par_scan_state()->hash_seed(), obj_to_scan)) { - par_scan_state()->note_steal(); bool res = work_q->push(obj_to_scan); assert(res, "Empty queue should have room for a push."); - par_scan_state()->note_push(); // if successful, goto Start. continue; @@ -842,17 +891,6 @@ void ParNewGeneration::collect(bool full, } thread_state_set.reset(promotion_failed()); - if (PAR_STATS_ENABLED && ParallelGCVerbose) { - gclog_or_tty->print("Thread totals:\n" - " Pushes: %7d Pops: %7d Steals %7d (sum = %7d).\n", - thread_state_set.pushes(), thread_state_set.pops(), - thread_state_set.steals(), - thread_state_set.pops()+thread_state_set.steals()); - } - assert(thread_state_set.pushes() == thread_state_set.pops() - + thread_state_set.steals(), - "Or else the queues are leaky."); - // Process (weak) reference objects found during scavenge. ReferenceProcessor* rp = ref_processor(); IsAliveClosure is_alive(this); @@ -932,6 +970,11 @@ void ParNewGeneration::collect(bool full, gch->print_heap_change(gch_prev_used); } + if (PrintGCDetails && ParallelGCVerbose) { + TASKQUEUE_STATS_ONLY(thread_state_set.print_termination_stats()); + TASKQUEUE_STATS_ONLY(thread_state_set.print_taskqueue_stats()); + } + if (UseAdaptiveSizePolicy) { size_policy->minor_collection_end(gch->gc_cause()); size_policy->avg_survived()->sample(from()->used()); @@ -1104,9 +1147,8 @@ oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo( gclog_or_tty->print("queue overflow!\n"); } push_on_overflow_list(old, par_scan_state); - par_scan_state->note_overflow_push(); + TASKQUEUE_STATS_ONLY(par_scan_state->taskqueue_stats().record_overflow(0)); } - par_scan_state->note_push(); return new_obj; } @@ -1227,9 +1269,8 @@ oop ParNewGeneration::copy_to_survivor_space_with_undo( if (simulate_overflow || !par_scan_state->work_queue()->push(obj_to_push)) { // Add stats for overflow pushes. push_on_overflow_list(old, par_scan_state); - par_scan_state->note_overflow_push(); + TASKQUEUE_STATS_ONLY(par_scan_state->taskqueue_stats().record_overflow(0)); } - par_scan_state->note_push(); return new_obj; } @@ -1466,7 +1507,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan cur = next; n++; } - par_scan_state->note_overflow_refill(n); + TASKQUEUE_STATS_ONLY(par_scan_state->note_overflow_refill(n)); #ifndef PRODUCT assert(_num_par_pushes >= n, "Too many pops?"); Atomic::add_ptr(-(intptr_t)n, &_num_par_pushes); diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp index 8196e621372..a3090ebf452 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp @@ -36,9 +36,6 @@ class ParEvacuateFollowersClosure; typedef Padded ObjToScanQueue; typedef GenericTaskQueueSet ObjToScanQueueSet; -// Enable this to get push/pop/steal stats. -const int PAR_STATS_ENABLED = 0; - class ParKeepAliveClosure: public DefNewGeneration::KeepAliveClosure { private: ParScanWeakRefClosure* _par_cl; @@ -94,8 +91,11 @@ class ParScanThreadState { bool _to_space_full; - int _pushes, _pops, _steals, _steal_attempts, _term_attempts; - int _overflow_pushes, _overflow_refills, _overflow_refill_objs; +#if TASKQUEUE_STATS + size_t _term_attempts; + size_t _overflow_refills; + size_t _overflow_refill_objs; +#endif // TASKQUEUE_STATS // Stats for promotion failure size_t _promotion_failure_size; @@ -181,45 +181,38 @@ class ParScanThreadState { } void print_and_clear_promotion_failure_size(); - int pushes() { return _pushes; } - int pops() { return _pops; } - int steals() { return _steals; } - int steal_attempts() { return _steal_attempts; } - int term_attempts() { return _term_attempts; } - int overflow_pushes() { return _overflow_pushes; } - int overflow_refills() { return _overflow_refills; } - int overflow_refill_objs() { return _overflow_refill_objs; } +#if TASKQUEUE_STATS + TaskQueueStats & taskqueue_stats() const { return _work_queue->stats; } - void note_push() { if (PAR_STATS_ENABLED) _pushes++; } - void note_pop() { if (PAR_STATS_ENABLED) _pops++; } - void note_steal() { if (PAR_STATS_ENABLED) _steals++; } - void note_steal_attempt() { if (PAR_STATS_ENABLED) _steal_attempts++; } - void note_term_attempt() { if (PAR_STATS_ENABLED) _term_attempts++; } - void note_overflow_push() { if (PAR_STATS_ENABLED) _overflow_pushes++; } - void note_overflow_refill(int objs) { - if (PAR_STATS_ENABLED) { - _overflow_refills++; - _overflow_refill_objs += objs; - } + size_t term_attempts() const { return _term_attempts; } + size_t overflow_refills() const { return _overflow_refills; } + size_t overflow_refill_objs() const { return _overflow_refill_objs; } + + void note_term_attempt() { ++_term_attempts; } + void note_overflow_refill(size_t objs) { + ++_overflow_refills; _overflow_refill_objs += objs; } + void reset_stats(); +#endif // TASKQUEUE_STATS + void start_strong_roots() { _start_strong_roots = os::elapsedTime(); } void end_strong_roots() { _strong_roots_time += (os::elapsedTime() - _start_strong_roots); } - double strong_roots_time() { return _strong_roots_time; } + double strong_roots_time() const { return _strong_roots_time; } void start_term_time() { - note_term_attempt(); + TASKQUEUE_STATS_ONLY(note_term_attempt()); _start_term = os::elapsedTime(); } void end_term_time() { _term_time += (os::elapsedTime() - _start_term); } - double term_time() { return _term_time; } + double term_time() const { return _term_time; } - double elapsed() { + double elapsed_time() const { return os::elapsedTime() - _start; } }; diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp index c87190d0ccb..e9da8d5fa66 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp @@ -123,7 +123,6 @@ void CardTableExtension::scavenge_contents(ObjectStartArray* start_array, assert(start_array != NULL && sp != NULL && pm != NULL, "Sanity"); assert(start_array->covered_region().contains(sp->used_region()), "ObjectStartArray does not cover space"); - bool depth_first = pm->depth_first(); if (sp->not_empty()) { oop* sp_top = (oop*)space_top; @@ -201,21 +200,12 @@ void CardTableExtension::scavenge_contents(ObjectStartArray* start_array, *first_nonclean_card++ = clean_card; } // scan oops in objects - // hoisted the if (depth_first) check out of the loop - if (depth_first){ - do { - oop(bottom_obj)->push_contents(pm); - bottom_obj += oop(bottom_obj)->size(); - assert(bottom_obj <= sp_top, "just checking"); - } while (bottom_obj < top); - pm->drain_stacks_cond_depth(); - } else { - do { - oop(bottom_obj)->copy_contents(pm); - bottom_obj += oop(bottom_obj)->size(); - assert(bottom_obj <= sp_top, "just checking"); - } while (bottom_obj < top); - } + do { + oop(bottom_obj)->push_contents(pm); + bottom_obj += oop(bottom_obj)->size(); + assert(bottom_obj <= sp_top, "just checking"); + } while (bottom_obj < top); + pm->drain_stacks_cond_depth(); // remember top oop* scanned prev_top = top; } @@ -230,7 +220,6 @@ void CardTableExtension::scavenge_contents_parallel(ObjectStartArray* start_arra uint stripe_number) { int ssize = 128; // Naked constant! Work unit = 64k. int dirty_card_count = 0; - bool depth_first = pm->depth_first(); oop* sp_top = (oop*)space_top; jbyte* start_card = byte_for(sp->bottom()); @@ -363,43 +352,22 @@ void CardTableExtension::scavenge_contents_parallel(ObjectStartArray* start_arra const int interval = PrefetchScanIntervalInBytes; // scan all objects in the range if (interval != 0) { - // hoisted the if (depth_first) check out of the loop - if (depth_first) { - while (p < to) { - Prefetch::write(p, interval); - oop m = oop(p); - assert(m->is_oop_or_null(), "check for header"); - m->push_contents(pm); - p += m->size(); - } - pm->drain_stacks_cond_depth(); - } else { - while (p < to) { - Prefetch::write(p, interval); - oop m = oop(p); - assert(m->is_oop_or_null(), "check for header"); - m->copy_contents(pm); - p += m->size(); - } + while (p < to) { + Prefetch::write(p, interval); + oop m = oop(p); + assert(m->is_oop_or_null(), "check for header"); + m->push_contents(pm); + p += m->size(); } + pm->drain_stacks_cond_depth(); } else { - // hoisted the if (depth_first) check out of the loop - if (depth_first) { - while (p < to) { - oop m = oop(p); - assert(m->is_oop_or_null(), "check for header"); - m->push_contents(pm); - p += m->size(); - } - pm->drain_stacks_cond_depth(); - } else { - while (p < to) { - oop m = oop(p); - assert(m->is_oop_or_null(), "check for header"); - m->copy_contents(pm); - p += m->size(); - } + while (p < to) { + oop m = oop(p); + assert(m->is_oop_or_null(), "check for header"); + m->push_contents(pm); + p += m->size(); } + pm->drain_stacks_cond_depth(); } last_scanned = p; } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/prefetchQueue.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/prefetchQueue.hpp deleted file mode 100644 index cd57b5ff8b3..00000000000 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/prefetchQueue.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -// -// PrefetchQueue is a FIFO queue of variable length (currently 8). -// -// We need to examine the performance penalty of variable lengths. -// We may also want to split this into cpu dependent bits. -// - -const int PREFETCH_QUEUE_SIZE = 8; - -class PrefetchQueue : public CHeapObj { - private: - void* _prefetch_queue[PREFETCH_QUEUE_SIZE]; - uint _prefetch_index; - - public: - int length() { return PREFETCH_QUEUE_SIZE; } - - inline void clear() { - for(int i=0; i inline void* push_and_pop(T* p) { - oop o = oopDesc::load_decode_heap_oop_not_null(p); - Prefetch::write(o->mark_addr(), 0); - // This prefetch is intended to make sure the size field of array - // oops is in cache. It assumes the the object layout is - // mark -> klass -> size, and that mark and klass are heapword - // sized. If this should change, this prefetch will need updating! - Prefetch::write(o->mark_addr() + (HeapWordSize*2), 0); - _prefetch_queue[_prefetch_index++] = p; - _prefetch_index &= (PREFETCH_QUEUE_SIZE-1); - return _prefetch_queue[_prefetch_index]; - } - - // Stores a NULL pointer in the pop'd location. - inline void* pop() { - _prefetch_queue[_prefetch_index++] = NULL; - _prefetch_index &= (PREFETCH_QUEUE_SIZE-1); - return _prefetch_queue[_prefetch_index]; - } -}; diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp index 2da32555dee..1e73d11d1e3 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp @@ -27,7 +27,6 @@ PSPromotionManager** PSPromotionManager::_manager_array = NULL; OopStarTaskQueueSet* PSPromotionManager::_stack_array_depth = NULL; -OopTaskQueueSet* PSPromotionManager::_stack_array_breadth = NULL; PSOldGen* PSPromotionManager::_old_gen = NULL; MutableSpace* PSPromotionManager::_young_space = NULL; @@ -42,23 +41,14 @@ void PSPromotionManager::initialize() { _manager_array = NEW_C_HEAP_ARRAY(PSPromotionManager*, ParallelGCThreads+1 ); guarantee(_manager_array != NULL, "Could not initialize promotion manager"); - if (UseDepthFirstScavengeOrder) { - _stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads); - guarantee(_stack_array_depth != NULL, "Count not initialize promotion manager"); - } else { - _stack_array_breadth = new OopTaskQueueSet(ParallelGCThreads); - guarantee(_stack_array_breadth != NULL, "Count not initialize promotion manager"); - } + _stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads); + guarantee(_stack_array_depth != NULL, "Cound not initialize promotion manager"); // Create and register the PSPromotionManager(s) for the worker threads. for(uint i=0; iregister_queue(i, _manager_array[i]->claimed_stack_depth()); - } else { - stack_array_breadth()->register_queue(i, _manager_array[i]->claimed_stack_breadth()); - } + stack_array_depth()->register_queue(i, _manager_array[i]->claimed_stack_depth()); } // The VMThread gets its own PSPromotionManager, which is not available @@ -93,11 +83,7 @@ void PSPromotionManager::post_scavenge() { TASKQUEUE_STATS_ONLY(if (PrintGCDetails && ParallelGCVerbose) print_stats()); for (uint i = 0; i < ParallelGCThreads + 1; i++) { PSPromotionManager* manager = manager_array(i); - if (UseDepthFirstScavengeOrder) { - assert(manager->claimed_stack_depth()->is_empty(), "should be empty"); - } else { - assert(manager->claimed_stack_breadth()->is_empty(), "should be empty"); - } + assert(manager->claimed_stack_depth()->is_empty(), "should be empty"); manager->flush_labs(); } } @@ -105,10 +91,8 @@ void PSPromotionManager::post_scavenge() { #if TASKQUEUE_STATS void PSPromotionManager::print_taskqueue_stats(uint i) const { - const TaskQueueStats& stats = depth_first() ? - _claimed_stack_depth.stats : _claimed_stack_breadth.stats; tty->print("%3u ", i); - stats.print(); + _claimed_stack_depth.stats.print(); tty->cr(); } @@ -128,8 +112,7 @@ static const char* const pm_stats_hdr[] = { void PSPromotionManager::print_stats() { - const bool df = UseDepthFirstScavengeOrder; - tty->print_cr("== GC Task Stats (%s-First), GC %3d", df ? "Depth" : "Breadth", + tty->print_cr("== GC Tasks Stats, GC %3d", Universe::heap()->total_collections()); tty->print("thr "); TaskQueueStats::print_header(1); tty->cr(); @@ -147,9 +130,7 @@ PSPromotionManager::print_stats() { void PSPromotionManager::reset_stats() { - TaskQueueStats& stats = depth_first() ? - claimed_stack_depth()->stats : claimed_stack_breadth()->stats; - stats.reset(); + claimed_stack_depth()->stats.reset(); _masked_pushes = _masked_steals = 0; _arrays_chunked = _array_chunks_processed = 0; } @@ -158,19 +139,13 @@ PSPromotionManager::reset_stats() { PSPromotionManager::PSPromotionManager() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - _depth_first = UseDepthFirstScavengeOrder; // We set the old lab's start array. _old_lab.set_start_array(old_gen()->start_array()); uint queue_size; - if (depth_first()) { - claimed_stack_depth()->initialize(); - queue_size = claimed_stack_depth()->max_elems(); - } else { - claimed_stack_breadth()->initialize(); - queue_size = claimed_stack_breadth()->max_elems(); - } + claimed_stack_depth()->initialize(); + queue_size = claimed_stack_depth()->max_elems(); _totally_drain = (ParallelGCThreads == 1) || (GCDrainStackTargetSize == 0); if (_totally_drain) { @@ -205,14 +180,11 @@ void PSPromotionManager::reset() { _old_lab.initialize(MemRegion(lab_base, (size_t)0)); _old_gen_is_full = false; - _prefetch_queue.clear(); - TASKQUEUE_STATS_ONLY(reset_stats()); } void PSPromotionManager::drain_stacks_depth(bool totally_drain) { - assert(depth_first(), "invariant"); assert(claimed_stack_depth()->overflow_stack() != NULL, "invariant"); totally_drain = totally_drain || _totally_drain; @@ -250,50 +222,6 @@ void PSPromotionManager::drain_stacks_depth(bool totally_drain) { assert(tq->overflow_empty(), "Sanity"); } -void PSPromotionManager::drain_stacks_breadth(bool totally_drain) { - assert(!depth_first(), "invariant"); - assert(claimed_stack_breadth()->overflow_stack() != NULL, "invariant"); - totally_drain = totally_drain || _totally_drain; - -#ifdef ASSERT - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - MutableSpace* to_space = heap->young_gen()->to_space(); - MutableSpace* old_space = heap->old_gen()->object_space(); - MutableSpace* perm_space = heap->perm_gen()->object_space(); -#endif /* ASSERT */ - - OverflowTaskQueue* const tq = claimed_stack_breadth(); - do { - oop obj; - - // Drain overflow stack first, so other threads can steal from - // claimed stack while we work. - while (tq->pop_overflow(obj)) { - obj->copy_contents(this); - } - - if (totally_drain) { - while (tq->pop_local(obj)) { - obj->copy_contents(this); - } - } else { - while (tq->size() > _target_stack_size && tq->pop_local(obj)) { - obj->copy_contents(this); - } - } - - // If we could not find any other work, flush the prefetch queue - if (tq->is_empty()) { - flush_prefetch_queue(); - } - } while (totally_drain && !tq->taskqueue_empty() || !tq->overflow_empty()); - - assert(!totally_drain || tq->taskqueue_empty(), "Sanity"); - assert(totally_drain || tq->size() <= _target_stack_size, "Sanity"); - assert(tq->overflow_empty(), "Sanity"); -} - void PSPromotionManager::flush_labs() { assert(stacks_empty(), "Attempt to flush lab with live stack"); @@ -319,7 +247,7 @@ void PSPromotionManager::flush_labs() { // performance. // -oop PSPromotionManager::copy_to_survivor_space(oop o, bool depth_first) { +oop PSPromotionManager::copy_to_survivor_space(oop o) { assert(PSScavenge::should_scavenge(&o), "Sanity"); oop new_obj = NULL; @@ -423,24 +351,20 @@ oop PSPromotionManager::copy_to_survivor_space(oop o, bool depth_first) { assert(young_space()->contains(new_obj), "Attempt to push non-promoted obj"); } - if (depth_first) { - // Do the size comparison first with new_obj_size, which we - // already have. Hopefully, only a few objects are larger than - // _min_array_size_for_chunking, and most of them will be arrays. - // So, the is->objArray() test would be very infrequent. - if (new_obj_size > _min_array_size_for_chunking && - new_obj->is_objArray() && - PSChunkLargeArrays) { - // we'll chunk it - oop* const masked_o = mask_chunked_array_oop(o); - push_depth(masked_o); - TASKQUEUE_STATS_ONLY(++_arrays_chunked; ++_masked_pushes); - } else { - // we'll just push its contents - new_obj->push_contents(this); - } + // Do the size comparison first with new_obj_size, which we + // already have. Hopefully, only a few objects are larger than + // _min_array_size_for_chunking, and most of them will be arrays. + // So, the is->objArray() test would be very infrequent. + if (new_obj_size > _min_array_size_for_chunking && + new_obj->is_objArray() && + PSChunkLargeArrays) { + // we'll chunk it + oop* const masked_o = mask_chunked_array_oop(o); + push_depth(masked_o); + TASKQUEUE_STATS_ONLY(++_arrays_chunked; ++_masked_pushes); } else { - push_breadth(new_obj); + // we'll just push its contents + new_obj->push_contents(this); } } else { // We lost, someone else "owns" this object @@ -537,13 +461,7 @@ oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) { // We won any races, we "own" this object. assert(obj == obj->forwardee(), "Sanity"); - if (depth_first()) { - obj->push_contents(this); - } else { - // Don't bother incrementing the age, just push - // onto the claimed_stack.. - push_breadth(obj); - } + obj->push_contents(this); // Save the mark if needed PSScavenge::oop_promotion_failed(obj, obj_mark); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp index ec89b9557bb..aa14478d480 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp @@ -48,7 +48,6 @@ class PSPromotionManager : public CHeapObj { private: static PSPromotionManager** _manager_array; static OopStarTaskQueueSet* _stack_array_depth; - static OopTaskQueueSet* _stack_array_breadth; static PSOldGen* _old_gen; static MutableSpace* _young_space; @@ -69,12 +68,10 @@ class PSPromotionManager : public CHeapObj { PSOldPromotionLAB _old_lab; bool _young_gen_is_full; bool _old_gen_is_full; - PrefetchQueue _prefetch_queue; OopStarTaskQueue _claimed_stack_depth; OverflowTaskQueue _claimed_stack_breadth; - bool _depth_first; bool _totally_drain; uint _target_stack_size; @@ -87,7 +84,6 @@ class PSPromotionManager : public CHeapObj { inline static PSPromotionManager* manager_array(int index); template inline void claim_or_forward_internal_depth(T* p); - template inline void claim_or_forward_internal_breadth(T* p); // On the task queues we push reference locations as well as // partially-scanned arrays (in the latter case, we push an oop to @@ -136,19 +132,11 @@ class PSPromotionManager : public CHeapObj { void process_array_chunk(oop old); template void push_depth(T* p) { - assert(depth_first(), "pre-condition"); claimed_stack_depth()->push(p); } - void push_breadth(oop o) { - assert(!depth_first(), "pre-condition"); - claimed_stack_breadth()->push(o); - } - protected: static OopStarTaskQueueSet* stack_array_depth() { return _stack_array_depth; } - static OopTaskQueueSet* stack_array_breadth() { return _stack_array_breadth; } - public: // Static static void initialize(); @@ -163,19 +151,12 @@ class PSPromotionManager : public CHeapObj { return stack_array_depth()->steal(queue_num, seed, t); } - static bool steal_breadth(int queue_num, int* seed, oop& t) { - return stack_array_breadth()->steal(queue_num, seed, t); - } - PSPromotionManager(); // Accessors OopStarTaskQueue* claimed_stack_depth() { return &_claimed_stack_depth; } - OverflowTaskQueue* claimed_stack_breadth() { - return &_claimed_stack_breadth; - } bool young_gen_is_full() { return _young_gen_is_full; } @@ -183,18 +164,14 @@ class PSPromotionManager : public CHeapObj { void set_old_gen_is_full(bool state) { _old_gen_is_full = state; } // Promotion methods - oop copy_to_survivor_space(oop o, bool depth_first); + oop copy_to_survivor_space(oop o); oop oop_promotion_failed(oop obj, markOop obj_mark); void reset(); void flush_labs(); void drain_stacks(bool totally_drain) { - if (depth_first()) { - drain_stacks_depth(totally_drain); - } else { - drain_stacks_breadth(totally_drain); - } + drain_stacks_depth(totally_drain); } public: void drain_stacks_cond_depth() { @@ -203,22 +180,14 @@ class PSPromotionManager : public CHeapObj { } } void drain_stacks_depth(bool totally_drain); - void drain_stacks_breadth(bool totally_drain); - bool depth_first() const { - return _depth_first; - } bool stacks_empty() { - return depth_first() ? - claimed_stack_depth()->is_empty() : - claimed_stack_breadth()->is_empty(); + return claimed_stack_depth()->is_empty(); } inline void process_popped_location_depth(StarTask p); - inline void flush_prefetch_queue(); template inline void claim_or_forward_depth(T* p); - template inline void claim_or_forward_breadth(T* p); TASKQUEUE_STATS_ONLY(inline void record_steal(StarTask& p);) }; diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp index ea81c817b30..decc5e99a46 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp @@ -45,33 +45,8 @@ inline void PSPromotionManager::claim_or_forward_internal_depth(T* p) { } } -template -inline void PSPromotionManager::claim_or_forward_internal_breadth(T* p) { - if (p != NULL) { // XXX: error if p != NULL here - oop o = oopDesc::load_decode_heap_oop_not_null(p); - if (o->is_forwarded()) { - o = o->forwardee(); - } else { - o = copy_to_survivor_space(o, false); - } - // Card mark - if (PSScavenge::is_obj_in_young((HeapWord*) o)) { - PSScavenge::card_table()->inline_write_ref_field_gc(p, o); - } - oopDesc::encode_store_heap_oop_not_null(p, o); - } -} - -inline void PSPromotionManager::flush_prefetch_queue() { - assert(!depth_first(), "invariant"); - for (int i = 0; i < _prefetch_queue.length(); i++) { - claim_or_forward_internal_breadth((oop*)_prefetch_queue.pop()); - } -} - template inline void PSPromotionManager::claim_or_forward_depth(T* p) { - assert(depth_first(), "invariant"); assert(PSScavenge::should_scavenge(p, true), "revisiting object?"); assert(Universe::heap()->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); @@ -80,36 +55,6 @@ inline void PSPromotionManager::claim_or_forward_depth(T* p) { claim_or_forward_internal_depth(p); } -template -inline void PSPromotionManager::claim_or_forward_breadth(T* p) { - assert(!depth_first(), "invariant"); - assert(PSScavenge::should_scavenge(p, true), "revisiting object?"); - assert(Universe::heap()->kind() == CollectedHeap::ParallelScavengeHeap, - "Sanity"); - assert(Universe::heap()->is_in(p), "pointer outside heap"); - - if (UsePrefetchQueue) { - claim_or_forward_internal_breadth((T*)_prefetch_queue.push_and_pop(p)); - } else { - // This option is used for testing. The use of the prefetch - // queue can delay the processing of the objects and thus - // change the order of object scans. For example, remembered - // set updates are typically the clearing of the remembered - // set (the cards) followed by updates of the remembered set - // for young-to-old pointers. In a situation where there - // is an error in the sequence of clearing and updating - // (e.g. clear card A, update card A, erroneously clear - // card A again) the error can be obscured by a delay - // in the update due to the use of the prefetch queue - // (e.g., clear card A, erroneously clear card A again, - // update card A that was pushed into the prefetch queue - // and thus delayed until after the erronous clear). The - // length of the delay is random depending on the objects - // in the queue and the delay can be zero. - claim_or_forward_internal_breadth(p); - } -} - inline void PSPromotionManager::process_popped_location_depth(StarTask p) { if (is_oop_masked(p)) { assert(PSChunkLargeArrays, "invariant"); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp index 9cc02479d91..0ea076812b0 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp @@ -157,10 +157,8 @@ void PSRefProcTaskExecutor::execute(ProcessTask& task) q->enqueue(new PSRefProcTaskProxy(task, i)); } ParallelTaskTerminator terminator( - ParallelScavengeHeap::gc_task_manager()->workers(), - UseDepthFirstScavengeOrder ? - (TaskQueueSetSuper*) PSPromotionManager::stack_array_depth() - : (TaskQueueSetSuper*) PSPromotionManager::stack_array_breadth()); + ParallelScavengeHeap::gc_task_manager()->workers(), + (TaskQueueSetSuper*) PSPromotionManager::stack_array_depth()); if (task.marks_oops_alive() && ParallelGCThreads > 1) { for (uint j=0; jenqueue(new StealTask(&terminator)); @@ -375,10 +373,8 @@ bool PSScavenge::invoke_no_policy() { q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::code_cache)); ParallelTaskTerminator terminator( - gc_task_manager()->workers(), - promotion_manager->depth_first() ? - (TaskQueueSetSuper*) promotion_manager->stack_array_depth() - : (TaskQueueSetSuper*) promotion_manager->stack_array_breadth()); + gc_task_manager()->workers(), + (TaskQueueSetSuper*) promotion_manager->stack_array_depth()); if (ParallelGCThreads>1) { for (uint j=0; jenqueue(new StealTask(&terminator)); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp index 7dcf93a9540..3de87882fa5 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp @@ -65,7 +65,7 @@ inline void PSScavenge::copy_and_push_safe_barrier(PSPromotionManager* pm, oop o = oopDesc::load_decode_heap_oop_not_null(p); oop new_obj = o->is_forwarded() ? o->forwardee() - : pm->copy_to_survivor_space(o, pm->depth_first()); + : pm->copy_to_survivor_space(o); oopDesc::encode_store_heap_oop_not_null(p, new_obj); // We cannot mark without test, as some code passes us pointers diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp index 6f72724bfda..11774d941f1 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp @@ -144,29 +144,15 @@ void StealTask::do_it(GCTaskManager* manager, uint which) { "stacks should be empty at this point"); int random_seed = 17; - if (pm->depth_first()) { - while(true) { - StarTask p; - if (PSPromotionManager::steal_depth(which, &random_seed, p)) { - TASKQUEUE_STATS_ONLY(pm->record_steal(p)); - pm->process_popped_location_depth(p); - pm->drain_stacks_depth(true); - } else { - if (terminator()->offer_termination()) { - break; - } - } - } - } else { - while(true) { - oop obj; - if (PSPromotionManager::steal_breadth(which, &random_seed, obj)) { - obj->copy_contents(pm); - pm->drain_stacks_breadth(true); - } else { - if (terminator()->offer_termination()) { - break; - } + while(true) { + StarTask p; + if (PSPromotionManager::steal_depth(which, &random_seed, p)) { + TASKQUEUE_STATS_ONLY(pm->record_steal(p)); + pm->process_popped_location_depth(p); + pm->drain_stacks_depth(true); + } else { + if (terminator()->offer_termination()) { + break; } } } diff --git a/hotspot/src/share/vm/includeDB_compiler1 b/hotspot/src/share/vm/includeDB_compiler1 index bdfea08070c..18ff024df70 100644 --- a/hotspot/src/share/vm/includeDB_compiler1 +++ b/hotspot/src/share/vm/includeDB_compiler1 @@ -19,7 +19,6 @@ // Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA // or visit www.oracle.com if you need additional information or have any // questions. -// // // NOTE: DO NOT CHANGE THIS COPYRIGHT TO NEW STYLE - IT WILL BREAK makeDeps! diff --git a/hotspot/src/share/vm/includeDB_compiler2 b/hotspot/src/share/vm/includeDB_compiler2 index 33bb7152cda..59e1794a873 100644 --- a/hotspot/src/share/vm/includeDB_compiler2 +++ b/hotspot/src/share/vm/includeDB_compiler2 @@ -1,5 +1,5 @@ // -// Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -504,6 +504,7 @@ graphKit.hpp addnode.hpp graphKit.hpp callnode.hpp graphKit.hpp cfgnode.hpp graphKit.hpp ciEnv.hpp +graphKit.hpp ciMethodData.hpp graphKit.hpp divnode.hpp graphKit.hpp compile.hpp graphKit.hpp deoptimization.hpp @@ -624,6 +625,7 @@ loopTransform.cpp divnode.hpp loopTransform.cpp loopnode.hpp loopTransform.cpp mulnode.hpp loopTransform.cpp rootnode.hpp +loopTransform.cpp runtime.hpp loopTransform.cpp subnode.hpp loopUnswitch.cpp allocation.inline.hpp diff --git a/hotspot/src/share/vm/includeDB_core b/hotspot/src/share/vm/includeDB_core index fe4252dfcfd..faf7843fcb2 100644 --- a/hotspot/src/share/vm/includeDB_core +++ b/hotspot/src/share/vm/includeDB_core @@ -225,7 +225,6 @@ arrayOop.cpp oop.inline.hpp arrayOop.cpp symbolOop.hpp arrayOop.hpp oop.hpp -arrayOop.hpp universe.hpp arrayOop.hpp universe.inline.hpp assembler.cpp assembler.hpp @@ -236,7 +235,6 @@ assembler.cpp icache.hpp assembler.cpp os.hpp assembler.hpp allocation.hpp -assembler.hpp allocation.inline.hpp assembler.hpp debug.hpp assembler.hpp growableArray.hpp assembler.hpp oopRecorder.hpp @@ -330,7 +328,7 @@ blockOffsetTable.cpp collectedHeap.inline.hpp blockOffsetTable.cpp iterator.hpp blockOffsetTable.cpp java.hpp blockOffsetTable.cpp oop.inline.hpp -blockOffsetTable.cpp space.hpp +blockOffsetTable.cpp space.inline.hpp blockOffsetTable.cpp universe.hpp blockOffsetTable.hpp globalDefinitions.hpp @@ -338,6 +336,7 @@ blockOffsetTable.hpp memRegion.hpp blockOffsetTable.hpp virtualspace.hpp blockOffsetTable.inline.hpp blockOffsetTable.hpp +blockOffsetTable.inline.hpp safepoint.hpp blockOffsetTable.inline.hpp space.hpp bytecode.cpp bytecode.hpp @@ -1082,6 +1081,8 @@ compilationPolicy.cpp nativeLookup.hpp compilationPolicy.cpp nmethod.hpp compilationPolicy.cpp oop.inline.hpp compilationPolicy.cpp rframe.hpp +compilationPolicy.cpp scopeDesc.hpp +compilationPolicy.cpp simpleThresholdPolicy.hpp compilationPolicy.cpp stubRoutines.hpp compilationPolicy.cpp thread.hpp compilationPolicy.cpp timer.hpp @@ -1452,6 +1453,7 @@ defaultStream.hpp xmlstream.hpp deoptimization.cpp allocation.inline.hpp deoptimization.cpp biasedLocking.hpp deoptimization.cpp bytecode.hpp +deoptimization.cpp compilationPolicy.hpp deoptimization.cpp debugInfoRec.hpp deoptimization.cpp deoptimization.hpp deoptimization.cpp events.hpp @@ -1807,7 +1809,7 @@ generateOopMap.hpp signature.hpp generateOopMap.hpp universe.inline.hpp generation.cpp allocation.inline.hpp -generation.cpp blockOffsetTable.hpp +generation.cpp blockOffsetTable.inline.hpp generation.cpp cardTableRS.hpp generation.cpp collectedHeap.inline.hpp generation.cpp copy.hpp @@ -2173,6 +2175,7 @@ interpreterRT_.hpp generate_platform_dependent_include interpreterRuntime.cpp biasedLocking.hpp interpreterRuntime.cpp collectedHeap.hpp +interpreterRuntime.cpp compileBroker.hpp interpreterRuntime.cpp compilationPolicy.hpp interpreterRuntime.cpp constantPoolOop.hpp interpreterRuntime.cpp cpCacheOop.hpp @@ -2830,6 +2833,7 @@ methodDataKlass.hpp klass.hpp methodDataOop.cpp bytecode.hpp methodDataOop.cpp bytecodeStream.hpp +methodDataOop.cpp compilationPolicy.hpp methodDataOop.cpp deoptimization.hpp methodDataOop.cpp handles.inline.hpp methodDataOop.cpp linkResolver.hpp @@ -2842,6 +2846,7 @@ methodDataOop.hpp bytecodes.hpp methodDataOop.hpp oop.hpp methodDataOop.hpp orderAccess.hpp methodDataOop.hpp universe.hpp +methodDataOop.hpp methodOop.hpp methodHandleWalk.hpp methodHandles.hpp @@ -2907,6 +2912,7 @@ methodOop.cpp bytecodeStream.hpp methodOop.cpp bytecodeTracer.hpp methodOop.cpp bytecodes.hpp methodOop.cpp collectedHeap.inline.hpp +methodOop.cpp compilationPolicy.hpp methodOop.cpp debugInfoRec.hpp methodOop.cpp frame.inline.hpp methodOop.cpp gcLocker.hpp @@ -3436,7 +3442,7 @@ perfMemory_.cpp perfMemory.hpp perfMemory_.cpp resourceArea.hpp perfMemory_.cpp vmSymbols.hpp -permGen.cpp blockOffsetTable.hpp +permGen.cpp blockOffsetTable.inline.hpp permGen.cpp cSpaceCounters.hpp permGen.cpp collectedHeap.inline.hpp permGen.cpp compactPermGen.hpp @@ -3656,6 +3662,7 @@ runtimeService.hpp timer.hpp safepoint.cpp codeCache.hpp safepoint.cpp collectedHeap.hpp +safepoint.cpp compilationPolicy.hpp safepoint.cpp deoptimization.hpp safepoint.cpp events.hpp safepoint.cpp frame.inline.hpp @@ -3800,12 +3807,23 @@ signature.hpp allocation.hpp signature.hpp methodOop.hpp signature.hpp top.hpp +simpleThresholdPolicy.cpp arguments.hpp +simpleThresholdPolicy.cpp compileBroker.hpp +simpleThresholdPolicy.cpp resourceArea.hpp +simpleThresholdPolicy.cpp simpleThresholdPolicy.hpp +simpleThresholdPolicy.cpp simpleThresholdPolicy.inline.hpp + +simpleThresholdPolicy.hpp compilationPolicy.hpp +simpleThresholdPolicy.hpp globalDefinitions.hpp +simpleThresholdPolicy.hpp methodDataOop.hpp +simpleThresholdPolicy.hpp nmethod.hpp + sizes.cpp sizes.hpp sizes.hpp allocation.hpp sizes.hpp globalDefinitions.hpp -space.cpp blockOffsetTable.hpp +space.cpp blockOffsetTable.inline.hpp space.cpp copy.hpp space.cpp defNewGeneration.hpp space.cpp genCollectedHeap.hpp @@ -3835,7 +3853,6 @@ space.hpp prefetch.hpp space.hpp watermark.hpp space.hpp workgroup.hpp -space.inline.hpp blockOffsetTable.inline.hpp space.inline.hpp collectedHeap.hpp space.inline.hpp safepoint.hpp space.inline.hpp space.hpp @@ -3979,6 +3996,7 @@ stubs.hpp os_.inline.hpp sweeper.cpp atomic.hpp sweeper.cpp codeCache.hpp +sweeper.cpp compilationPolicy.hpp sweeper.cpp compileBroker.hpp sweeper.cpp events.hpp sweeper.cpp methodOop.hpp diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 29b4ede2bd9..9581f24bc30 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -421,7 +421,9 @@ BytecodeInterpreter::run(interpreterState istate) { #ifdef ASSERT if (istate->_msg != initialize) { assert(abs(istate->_stack_base - istate->_stack_limit) == (istate->_method->max_stack() + 1), "bad stack limit"); - IA32_ONLY(assert(istate->_stack_limit == istate->_thread->last_Java_sp() + 1, "wrong")); +#ifndef SHARK + IA32_ONLY(assert(istate->_stack_limit == istate->_thread->last_Java_sp() + 1, "wrong")); +#endif // !SHARK } // Verify linkages. interpreterState l = istate; diff --git a/hotspot/src/share/vm/interpreter/interpreter.hpp b/hotspot/src/share/vm/interpreter/interpreter.hpp index e8da2ce3123..606bbdfca1f 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.hpp +++ b/hotspot/src/share/vm/interpreter/interpreter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,7 +117,7 @@ class CodeletMark: ResourceMark { // commit Codelet - AbstractInterpreter::code()->commit((*_masm)->code()->pure_code_size()); + AbstractInterpreter::code()->commit((*_masm)->code()->pure_insts_size()); // make sure nobody can use _masm outside a CodeletMark lifespan *_masm = NULL; } diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index c156bbb3792..fd867a4cfd0 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -200,6 +200,7 @@ IRT_END void InterpreterRuntime::note_trap(JavaThread* thread, int reason, TRAPS) { assert(ProfileTraps, "call me only if profiling"); methodHandle trap_method(thread, method(thread)); + if (trap_method.not_null()) { methodDataHandle trap_mdo(thread, trap_method->method_data()); if (trap_mdo.is_null()) { @@ -777,43 +778,6 @@ IRT_END // Miscellaneous -#ifndef PRODUCT -static void trace_frequency_counter_overflow(methodHandle m, int branch_bci, int bci, address branch_bcp) { - if (TraceInvocationCounterOverflow) { - InvocationCounter* ic = m->invocation_counter(); - InvocationCounter* bc = m->backedge_counter(); - ResourceMark rm; - const char* msg = - branch_bcp == NULL - ? "comp-policy cntr ovfl @ %d in entry of " - : "comp-policy cntr ovfl @ %d in loop of "; - tty->print(msg, bci); - m->print_value(); - tty->cr(); - ic->print(); - bc->print(); - if (ProfileInterpreter) { - if (branch_bcp != NULL) { - methodDataOop mdo = m->method_data(); - if (mdo != NULL) { - int count = mdo->bci_to_data(branch_bci)->as_JumpData()->taken(); - tty->print_cr("back branch count = %d", count); - } - } - } - } -} - -static void trace_osr_request(methodHandle method, nmethod* osr, int bci) { - if (TraceOnStackReplacement) { - ResourceMark rm; - tty->print(osr != NULL ? "Reused OSR entry for " : "Requesting OSR entry for "); - method->print_short_name(tty); - tty->print_cr(" at bci %d", bci); - } -} -#endif // !PRODUCT - nmethod* InterpreterRuntime::frequency_counter_overflow(JavaThread* thread, address branch_bcp) { nmethod* nm = frequency_counter_overflow_inner(thread, branch_bcp); assert(branch_bcp != NULL || nm == NULL, "always returns null for non OSR requests"); @@ -826,7 +790,7 @@ nmethod* InterpreterRuntime::frequency_counter_overflow(JavaThread* thread, addr frame fr = thread->last_frame(); methodOop method = fr.interpreter_frame_method(); int bci = method->bci_from(fr.interpreter_frame_bcp()); - nm = method->lookup_osr_nmethod_for(bci); + nm = method->lookup_osr_nmethod_for(bci, CompLevel_none, false); } return nm; } @@ -840,74 +804,32 @@ IRT_ENTRY(nmethod*, frame fr = thread->last_frame(); assert(fr.is_interpreted_frame(), "must come from interpreter"); methodHandle method(thread, fr.interpreter_frame_method()); - const int branch_bci = branch_bcp != NULL ? method->bci_from(branch_bcp) : 0; - const int bci = method->bci_from(fr.interpreter_frame_bcp()); - NOT_PRODUCT(trace_frequency_counter_overflow(method, branch_bci, bci, branch_bcp);) + const int branch_bci = branch_bcp != NULL ? method->bci_from(branch_bcp) : InvocationEntryBci; + const int bci = branch_bcp != NULL ? method->bci_from(fr.interpreter_frame_bcp()) : InvocationEntryBci; - if (JvmtiExport::can_post_interpreter_events()) { - if (thread->is_interp_only_mode()) { - // If certain JVMTI events (e.g. frame pop event) are requested then the - // thread is forced to remain in interpreted code. This is - // implemented partly by a check in the run_compiled_code - // section of the interpreter whether we should skip running - // compiled code, and partly by skipping OSR compiles for - // interpreted-only threads. - if (branch_bcp != NULL) { - CompilationPolicy::policy()->reset_counter_for_back_branch_event(method); - return NULL; - } - } - } + nmethod* osr_nm = CompilationPolicy::policy()->event(method, method, branch_bci, bci, CompLevel_none, thread); - if (branch_bcp == NULL) { - // when code cache is full, compilation gets switched off, UseCompiler - // is set to false - if (!method->has_compiled_code() && UseCompiler) { - CompilationPolicy::policy()->method_invocation_event(method, CHECK_NULL); - } else { - // Force counter overflow on method entry, even if no compilation - // happened. (The method_invocation_event call does this also.) - CompilationPolicy::policy()->reset_counter_for_invocation_event(method); - } - // compilation at an invocation overflow no longer goes and retries test for - // compiled method. We always run the loser of the race as interpreted. - // so return NULL - return NULL; - } else { - // counter overflow in a loop => try to do on-stack-replacement - nmethod* osr_nm = method->lookup_osr_nmethod_for(bci); - NOT_PRODUCT(trace_osr_request(method, osr_nm, bci);) - // when code cache is full, we should not compile any more... - if (osr_nm == NULL && UseCompiler) { - const int branch_bci = method->bci_from(branch_bcp); - CompilationPolicy::policy()->method_back_branch_event(method, branch_bci, bci, CHECK_NULL); - osr_nm = method->lookup_osr_nmethod_for(bci); - } - if (osr_nm == NULL) { - CompilationPolicy::policy()->reset_counter_for_back_branch_event(method); - return NULL; - } else { - // We may need to do on-stack replacement which requires that no - // monitors in the activation are biased because their - // BasicObjectLocks will need to migrate during OSR. Force - // unbiasing of all monitors in the activation now (even though - // the OSR nmethod might be invalidated) because we don't have a - // safepoint opportunity later once the migration begins. - if (UseBiasedLocking) { - ResourceMark rm; - GrowableArray* objects_to_revoke = new GrowableArray(); - for( BasicObjectLock *kptr = fr.interpreter_frame_monitor_end(); - kptr < fr.interpreter_frame_monitor_begin(); - kptr = fr.next_monitor_in_interpreter_frame(kptr) ) { - if( kptr->obj() != NULL ) { - objects_to_revoke->append(Handle(THREAD, kptr->obj())); - } + if (osr_nm != NULL) { + // We may need to do on-stack replacement which requires that no + // monitors in the activation are biased because their + // BasicObjectLocks will need to migrate during OSR. Force + // unbiasing of all monitors in the activation now (even though + // the OSR nmethod might be invalidated) because we don't have a + // safepoint opportunity later once the migration begins. + if (UseBiasedLocking) { + ResourceMark rm; + GrowableArray* objects_to_revoke = new GrowableArray(); + for( BasicObjectLock *kptr = fr.interpreter_frame_monitor_end(); + kptr < fr.interpreter_frame_monitor_begin(); + kptr = fr.next_monitor_in_interpreter_frame(kptr) ) { + if( kptr->obj() != NULL ) { + objects_to_revoke->append(Handle(THREAD, kptr->obj())); } - BiasedLocking::revoke(objects_to_revoke); } - return osr_nm; + BiasedLocking::revoke(objects_to_revoke); } } + return osr_nm; IRT_END IRT_LEAF(jint, InterpreterRuntime::bcp_to_di(methodOopDesc* method, address cur_bcp)) @@ -1124,7 +1046,7 @@ address SignatureHandlerLibrary::set_handler_blob() { if (handler_blob == NULL) { return NULL; } - address handler = handler_blob->instructions_begin(); + address handler = handler_blob->code_begin(); _handler_blob = handler_blob; _handler = handler; return handler; @@ -1140,7 +1062,7 @@ void SignatureHandlerLibrary::initialize() { BufferBlob* bb = BufferBlob::create("Signature Handler Temp Buffer", SignatureHandlerLibrary::buffer_size); - _buffer = bb->instructions_begin(); + _buffer = bb->code_begin(); _fingerprints = new(ResourceObj::C_HEAP)GrowableArray(32, true); _handlers = new(ResourceObj::C_HEAP)GrowableArray
(32, true); @@ -1148,16 +1070,16 @@ void SignatureHandlerLibrary::initialize() { address SignatureHandlerLibrary::set_handler(CodeBuffer* buffer) { address handler = _handler; - int code_size = buffer->pure_code_size(); - if (handler + code_size > _handler_blob->instructions_end()) { + int insts_size = buffer->pure_insts_size(); + if (handler + insts_size > _handler_blob->code_end()) { // get a new handler blob handler = set_handler_blob(); } if (handler != NULL) { - memcpy(handler, buffer->code_begin(), code_size); + memcpy(handler, buffer->insts_begin(), insts_size); pd_set_handler(handler); - ICache::invalidate_range(handler, code_size); - _handler = handler + code_size; + ICache::invalidate_range(handler, insts_size); + _handler = handler + insts_size; } return handler; } @@ -1196,8 +1118,8 @@ void SignatureHandlerLibrary::add(methodHandle method) { (method->is_static() ? "static" : "receiver"), method->name_and_sig_as_C_string(), fingerprint, - buffer.code_size()); - Disassembler::decode(handler, handler + buffer.code_size()); + buffer.insts_size()); + Disassembler::decode(handler, handler + buffer.insts_size()); #ifndef PRODUCT tty->print_cr(" --- associated result handler ---"); address rh_begin = Interpreter::result_handler(method()->result_type()); diff --git a/hotspot/src/share/vm/interpreter/invocationCounter.cpp b/hotspot/src/share/vm/interpreter/invocationCounter.cpp index 9ed10b54958..4d8351f80a4 100644 --- a/hotspot/src/share/vm/interpreter/invocationCounter.cpp +++ b/hotspot/src/share/vm/interpreter/invocationCounter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,8 +40,7 @@ void InvocationCounter::reset() { } void InvocationCounter::set_carry() { - _counter |= carry_mask; - + set_carry_flag(); // The carry bit now indicates that this counter had achieved a very // large value. Now reduce the value, so that the method can be // executed many more times before re-entering the VM. @@ -52,7 +51,6 @@ void InvocationCounter::set_carry() { if (old_count != new_count) set(state(), new_count); } - void InvocationCounter::set_state(State state) { assert(0 <= state && state < number_of_states, "illegal state"); int init = _init[state]; @@ -82,11 +80,6 @@ int InvocationCounter::InterpreterInvocationLimit; int InvocationCounter::InterpreterBackwardBranchLimit; int InvocationCounter::InterpreterProfileLimit; -// Tier1 limits -int InvocationCounter::Tier1InvocationLimit; -int InvocationCounter::Tier1BackEdgeLimit; - - const char* InvocationCounter::state_as_string(State state) { switch (state) { @@ -146,8 +139,6 @@ void InvocationCounter::reinitialize(bool delay_overflow) { InterpreterInvocationLimit = CompileThreshold << number_of_noncount_bits; InterpreterProfileLimit = ((CompileThreshold * InterpreterProfilePercentage) / 100)<< number_of_noncount_bits; - Tier1InvocationLimit = Tier2CompileThreshold << number_of_noncount_bits; - Tier1BackEdgeLimit = Tier2BackEdgeThreshold << number_of_noncount_bits; // When methodData is collected, the backward branch limit is compared against a // methodData counter, rather than an InvocationCounter. In the former case, we diff --git a/hotspot/src/share/vm/interpreter/invocationCounter.hpp b/hotspot/src/share/vm/interpreter/invocationCounter.hpp index 9912cfc9f50..2019d42124f 100644 --- a/hotspot/src/share/vm/interpreter/invocationCounter.hpp +++ b/hotspot/src/share/vm/interpreter/invocationCounter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,6 @@ class InvocationCounter VALUE_OBJ_CLASS_SPEC { number_of_count_bits = BitsPerInt - number_of_noncount_bits, state_limit = nth_bit(number_of_state_bits), count_grain = nth_bit(number_of_state_bits + number_of_carry_bits), - count_limit = nth_bit(number_of_count_bits - 1), carry_mask = right_n_bits(number_of_carry_bits) << number_of_state_bits, state_mask = right_n_bits(number_of_state_bits), status_mask = right_n_bits(number_of_state_bits + number_of_carry_bits), @@ -52,18 +51,16 @@ class InvocationCounter VALUE_OBJ_CLASS_SPEC { public: static int InterpreterInvocationLimit; // CompileThreshold scaled for interpreter use - static int Tier1InvocationLimit; // CompileThreshold scaled for tier1 use - static int Tier1BackEdgeLimit; // BackEdgeThreshold scaled for tier1 use - static int InterpreterBackwardBranchLimit; // A separate threshold for on stack replacement - static int InterpreterProfileLimit; // Profiling threshold scaled for interpreter use typedef address (*Action)(methodHandle method, TRAPS); enum PublicConstants { count_increment = count_grain, // use this value to increment the 32bit _counter word - count_mask_value = count_mask // use this value to mask the backedge counter + count_mask_value = count_mask, // use this value to mask the backedge counter + count_shift = number_of_noncount_bits, + count_limit = nth_bit(number_of_count_bits - 1) }; enum State { @@ -79,6 +76,7 @@ class InvocationCounter VALUE_OBJ_CLASS_SPEC { inline void set(State state, int count); // sets state and counter inline void decay(); // decay counter (divide by two) void set_carry(); // set the sticky carry bit + void set_carry_flag() { _counter |= carry_mask; } // Accessors State state() const { return (State)(_counter & state_mask); } @@ -135,3 +133,4 @@ inline void InvocationCounter::decay() { if (c > 0 && new_count == 0) new_count = 1; set(state(), new_count); } + diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 4a3669403f1..1542ab588d2 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,12 +83,12 @@ void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass _resolved_method = resolved_method; _selected_method = selected_method; _vtable_index = vtable_index; - if (CompilationPolicy::mustBeCompiled(selected_method)) { + if (CompilationPolicy::must_be_compiled(selected_method)) { // This path is unusual, mostly used by the '-Xcomp' stress test mode. - // Note: with several active threads, the mustBeCompiled may be true - // while canBeCompiled is false; remove assert - // assert(CompilationPolicy::canBeCompiled(selected_method), "cannot compile"); + // Note: with several active threads, the must_be_compiled may be true + // while can_be_compiled is false; remove assert + // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile"); if (THREAD->is_Compiler_thread()) { // don't force compilation, resolve was on behalf of compiler return; @@ -104,7 +104,8 @@ void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass return; } CompileBroker::compile_method(selected_method, InvocationEntryBci, - methodHandle(), 0, "mustBeCompiled", CHECK); + CompLevel_initial_compile, + methodHandle(), 0, "must_be_compiled", CHECK); } } diff --git a/hotspot/src/share/vm/memory/allocation.cpp b/hotspot/src/share/vm/memory/allocation.cpp index 6331bcefc78..9dfe26dd4d4 100644 --- a/hotspot/src/share/vm/memory/allocation.cpp +++ b/hotspot/src/share/vm/memory/allocation.cpp @@ -58,7 +58,7 @@ void* ResourceObj::operator new(size_t size, allocation_type type) { void ResourceObj::operator delete(void* p) { assert(((ResourceObj *)p)->allocated_on_C_heap(), "delete only allowed for C_HEAP objects"); - DEBUG_ONLY(((ResourceObj *)p)->_allocation = badHeapOopVal;) + DEBUG_ONLY(((ResourceObj *)p)->_allocation = (uintptr_t)badHeapOopVal;) FreeHeap(p); } @@ -104,7 +104,7 @@ ResourceObj& ResourceObj::operator=(const ResourceObj& r) { // default copy assi ResourceObj::~ResourceObj() { // allocated_on_C_heap() also checks that encoded (in _allocation) address == this. if (!allocated_on_C_heap()) { // ResourceObj::delete() zaps _allocation for C_heap. - _allocation = badHeapOopVal; // zap type + _allocation = (uintptr_t)badHeapOopVal; // zap type } } #endif // ASSERT diff --git a/hotspot/src/share/vm/memory/blockOffsetTable.cpp b/hotspot/src/share/vm/memory/blockOffsetTable.cpp index 03870202785..ee3ef125c52 100644 --- a/hotspot/src/share/vm/memory/blockOffsetTable.cpp +++ b/hotspot/src/share/vm/memory/blockOffsetTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,13 +103,13 @@ void BlockOffsetSharedArray::serialize(SerializeOopClosure* soc, ////////////////////////////////////////////////////////////////////// BlockOffsetArray::BlockOffsetArray(BlockOffsetSharedArray* array, - MemRegion mr, bool init_to_zero) : + MemRegion mr, bool init_to_zero_) : BlockOffsetTable(mr.start(), mr.end()), - _array(array), - _init_to_zero(init_to_zero) + _array(array) { assert(_bottom <= _end, "arguments out of order"); - if (!_init_to_zero) { + set_init_to_zero(init_to_zero_); + if (!init_to_zero_) { // initialize cards to point back to mr.start() set_remainder_to_point_to_start(mr.start() + N_words, mr.end()); _array->set_offset_array(0, 0); // set first card to 0 @@ -121,8 +121,9 @@ BlockOffsetArray::BlockOffsetArray(BlockOffsetSharedArray* array, // a right-open interval: [start, end) void BlockOffsetArray:: -set_remainder_to_point_to_start(HeapWord* start, HeapWord* end) { +set_remainder_to_point_to_start(HeapWord* start, HeapWord* end, bool reducing) { + check_reducing_assertion(reducing); if (start >= end) { // The start address is equal to the end address (or to // the right of the end address) so there are not cards @@ -167,7 +168,7 @@ set_remainder_to_point_to_start(HeapWord* start, HeapWord* end) { size_t end_card = _array->index_for(end-1); assert(start ==_array->address_for_index(start_card), "Precondition"); assert(end ==_array->address_for_index(end_card)+N_words, "Precondition"); - set_remainder_to_point_to_start_incl(start_card, end_card); // closed interval + set_remainder_to_point_to_start_incl(start_card, end_card, reducing); // closed interval } @@ -175,7 +176,9 @@ set_remainder_to_point_to_start(HeapWord* start, HeapWord* end) { // a closed, inclusive interval: [start_card, end_card], cf set_remainder_to_point_to_start() // above. void -BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t end_card) { +BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t end_card, bool reducing) { + + check_reducing_assertion(reducing); if (start_card > end_card) { return; } @@ -191,11 +194,11 @@ BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t size_t reach = start_card - 1 + (power_to_cards_back(i+1) - 1); offset = N_words + i; if (reach >= end_card) { - _array->set_offset_array(start_card_for_region, end_card, offset); + _array->set_offset_array(start_card_for_region, end_card, offset, reducing); start_card_for_region = reach + 1; break; } - _array->set_offset_array(start_card_for_region, reach, offset); + _array->set_offset_array(start_card_for_region, reach, offset, reducing); start_card_for_region = reach + 1; } assert(start_card_for_region > end_card, "Sanity check"); @@ -211,8 +214,10 @@ void BlockOffsetArray::check_all_cards(size_t start_card, size_t end_card) const return; } guarantee(_array->offset_array(start_card) == N_words, "Wrong value in second card"); + u_char last_entry = N_words; for (size_t c = start_card + 1; c <= end_card; c++ /* yeah! */) { u_char entry = _array->offset_array(c); + guarantee(entry >= last_entry, "Monotonicity"); if (c - start_card > power_to_cards_back(1)) { guarantee(entry > N_words, "Should be in logarithmic region"); } @@ -220,11 +225,13 @@ void BlockOffsetArray::check_all_cards(size_t start_card, size_t end_card) const size_t landing_card = c - backskip; guarantee(landing_card >= (start_card - 1), "Inv"); if (landing_card >= start_card) { - guarantee(_array->offset_array(landing_card) <= entry, "monotonicity"); + guarantee(_array->offset_array(landing_card) <= entry, "Monotonicity"); } else { - guarantee(landing_card == start_card - 1, "Tautology"); + guarantee(landing_card == (start_card - 1), "Tautology"); + // Note that N_words is the maximum offset value guarantee(_array->offset_array(landing_card) <= N_words, "Offset value"); } + last_entry = entry; // remember for monotonicity test } } @@ -243,7 +250,7 @@ BlockOffsetArray::alloc_block(HeapWord* blk_start, HeapWord* blk_end) { void BlockOffsetArray::do_block_internal(HeapWord* blk_start, HeapWord* blk_end, - Action action) { + Action action, bool reducing) { assert(Universe::heap()->is_in_reserved(blk_start), "reference must be into the heap"); assert(Universe::heap()->is_in_reserved(blk_end-1), @@ -275,18 +282,18 @@ BlockOffsetArray::do_block_internal(HeapWord* blk_start, switch (action) { case Action_mark: { if (init_to_zero()) { - _array->set_offset_array(start_index, boundary, blk_start); + _array->set_offset_array(start_index, boundary, blk_start, reducing); break; } // Else fall through to the next case } case Action_single: { - _array->set_offset_array(start_index, boundary, blk_start); + _array->set_offset_array(start_index, boundary, blk_start, reducing); // We have finished marking the "offset card". We need to now // mark the subsequent cards that this blk spans. if (start_index < end_index) { HeapWord* rem_st = _array->address_for_index(start_index) + N_words; HeapWord* rem_end = _array->address_for_index(end_index) + N_words; - set_remainder_to_point_to_start(rem_st, rem_end); + set_remainder_to_point_to_start(rem_st, rem_end, reducing); } break; } @@ -395,7 +402,7 @@ void BlockOffsetArrayNonContigSpace::split_block(HeapWord* blk, // Indices for starts of prefix block and suffix block. size_t pref_index = _array->index_for(pref_addr); if (_array->address_for_index(pref_index) != pref_addr) { - // pref_addr deos not begin pref_index + // pref_addr does not begin pref_index pref_index++; } @@ -430,18 +437,18 @@ void BlockOffsetArrayNonContigSpace::split_block(HeapWord* blk, if (num_suff_cards > 0) { HeapWord* boundary = _array->address_for_index(suff_index); // Set the offset card for suffix block - _array->set_offset_array(suff_index, boundary, suff_addr); + _array->set_offset_array(suff_index, boundary, suff_addr, true /* reducing */); // Change any further cards that need changing in the suffix if (num_pref_cards > 0) { if (num_pref_cards >= num_suff_cards) { // Unilaterally fix all of the suffix cards: closed card // index interval in args below. - set_remainder_to_point_to_start_incl(suff_index + 1, end_index - 1); + set_remainder_to_point_to_start_incl(suff_index + 1, end_index - 1, true /* reducing */); } else { // Unilaterally fix the first (num_pref_cards - 1) following // the "offset card" in the suffix block. set_remainder_to_point_to_start_incl(suff_index + 1, - suff_index + num_pref_cards - 1); + suff_index + num_pref_cards - 1, true /* reducing */); // Fix the appropriate cards in the remainder of the // suffix block -- these are the last num_pref_cards // cards in each power block of the "new" range plumbed @@ -461,7 +468,7 @@ void BlockOffsetArrayNonContigSpace::split_block(HeapWord* blk, // is non-null. if (left_index <= right_index) { _array->set_offset_array(left_index, right_index, - N_words + i - 1); + N_words + i - 1, true /* reducing */); } else { more = false; // we are done } @@ -482,7 +489,7 @@ void BlockOffsetArrayNonContigSpace::split_block(HeapWord* blk, more = false; } assert(left_index <= right_index, "Error"); - _array->set_offset_array(left_index, right_index, N_words + i - 1); + _array->set_offset_array(left_index, right_index, N_words + i - 1, true /* reducing */); i++; } } @@ -501,14 +508,13 @@ void BlockOffsetArrayNonContigSpace::split_block(HeapWord* blk, // any cards subsequent to the first one. void BlockOffsetArrayNonContigSpace::mark_block(HeapWord* blk_start, - HeapWord* blk_end) { - do_block_internal(blk_start, blk_end, Action_mark); + HeapWord* blk_end, bool reducing) { + do_block_internal(blk_start, blk_end, Action_mark, reducing); } HeapWord* BlockOffsetArrayNonContigSpace::block_start_unsafe( const void* addr) const { assert(_array->offset_array(0) == 0, "objects can't cross covered areas"); - assert(_bottom <= addr && addr < _end, "addr must be covered by this Array"); // Must read this exactly once because it can be modified by parallel @@ -542,9 +548,10 @@ HeapWord* BlockOffsetArrayNonContigSpace::block_start_unsafe( debug_only(HeapWord* last = q); // for debugging q = n; n += _sp->block_size(n); + assert(n > q, err_msg("Looping at: " INTPTR_FORMAT, n)); } - assert(q <= addr, "wrong order for current and arg"); - assert(addr <= n, "wrong order for arg and next"); + assert(q <= addr, err_msg("wrong order for current (" INTPTR_FORMAT ") <= arg (" INTPTR_FORMAT ")", q, addr)); + assert(addr <= n, err_msg("wrong order for arg (" INTPTR_FORMAT ") <= next (" INTPTR_FORMAT ")", addr, n)); return q; } @@ -727,9 +734,8 @@ void BlockOffsetArrayContigSpace::alloc_block_work(HeapWord* blk_start, _next_offset_index = end_index + 1; // Calculate _next_offset_threshold this way because end_index // may be the last valid index in the covered region. - _next_offset_threshold = _array->address_for_index(end_index) + - N_words; - assert(_next_offset_threshold >= blk_end, "Incorrent offset threshold"); + _next_offset_threshold = _array->address_for_index(end_index) + N_words; + assert(_next_offset_threshold >= blk_end, "Incorrect offset threshold"); #ifdef ASSERT // The offset can be 0 if the block starts on a boundary. That diff --git a/hotspot/src/share/vm/memory/blockOffsetTable.hpp b/hotspot/src/share/vm/memory/blockOffsetTable.hpp index db9461c5ef1..c0c78149a6b 100644 --- a/hotspot/src/share/vm/memory/blockOffsetTable.hpp +++ b/hotspot/src/share/vm/memory/blockOffsetTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,6 +107,8 @@ class BlockOffsetSharedArray: public CHeapObj { N_words = 1 << LogN_words }; + bool _init_to_zero; + // The reserved region covered by the shared array. MemRegion _reserved; @@ -125,17 +127,28 @@ class BlockOffsetSharedArray: public CHeapObj { assert(index < _vs.committed_size(), "index out of range"); return _offset_array[index]; } - void set_offset_array(size_t index, u_char offset) { + // An assertion-checking helper method for the set_offset_array() methods below. + void check_reducing_assertion(bool reducing); + + void set_offset_array(size_t index, u_char offset, bool reducing = false) { + check_reducing_assertion(reducing); assert(index < _vs.committed_size(), "index out of range"); + assert(!reducing || _offset_array[index] >= offset, "Not reducing"); _offset_array[index] = offset; } - void set_offset_array(size_t index, HeapWord* high, HeapWord* low) { + + void set_offset_array(size_t index, HeapWord* high, HeapWord* low, bool reducing = false) { + check_reducing_assertion(reducing); assert(index < _vs.committed_size(), "index out of range"); assert(high >= low, "addresses out of order"); assert(pointer_delta(high, low) <= N_words, "offset too large"); + assert(!reducing || _offset_array[index] >= (u_char)pointer_delta(high, low), + "Not reducing"); _offset_array[index] = (u_char)pointer_delta(high, low); } - void set_offset_array(HeapWord* left, HeapWord* right, u_char offset) { + + void set_offset_array(HeapWord* left, HeapWord* right, u_char offset, bool reducing = false) { + check_reducing_assertion(reducing); assert(index_for(right - 1) < _vs.committed_size(), "right address out of range"); assert(left < right, "Heap addresses out of order"); @@ -150,12 +163,15 @@ class BlockOffsetSharedArray: public CHeapObj { size_t i = index_for(left); const size_t end = i + num_cards; for (; i < end; i++) { + // Elided until CR 6977974 is fixed properly. + // assert(!reducing || _offset_array[i] >= offset, "Not reducing"); _offset_array[i] = offset; } } } - void set_offset_array(size_t left, size_t right, u_char offset) { + void set_offset_array(size_t left, size_t right, u_char offset, bool reducing = false) { + check_reducing_assertion(reducing); assert(right < _vs.committed_size(), "right address out of range"); assert(left <= right, "indexes out of order"); size_t num_cards = right - left + 1; @@ -169,6 +185,8 @@ class BlockOffsetSharedArray: public CHeapObj { size_t i = left; const size_t end = i + num_cards; for (; i < end; i++) { + // Elided until CR 6977974 is fixed properly. + // assert(!reducing || _offset_array[i] >= offset, "Not reducing"); _offset_array[i] = offset; } } @@ -212,6 +230,11 @@ public: void set_bottom(HeapWord* new_bottom); + // Whether entries should be initialized to zero. Used currently only for + // error checking. + void set_init_to_zero(bool val) { _init_to_zero = val; } + bool init_to_zero() { return _init_to_zero; } + // Updates all the BlockOffsetArray's sharing this shared array to // reflect the current "top"'s of their spaces. void update_offset_arrays(); // Not yet implemented! @@ -285,17 +308,23 @@ class BlockOffsetArray: public BlockOffsetTable { // initialized to point backwards to the beginning of the covered region. bool _init_to_zero; + // An assertion-checking helper method for the set_remainder*() methods below. + void check_reducing_assertion(bool reducing) { _array->check_reducing_assertion(reducing); } + // Sets the entries // corresponding to the cards starting at "start" and ending at "end" // to point back to the card before "start": the interval [start, end) - // is right-open. - void set_remainder_to_point_to_start(HeapWord* start, HeapWord* end); + // is right-open. The last parameter, reducing, indicates whether the + // updates to individual entries always reduce the entry from a higher + // to a lower value. (For example this would hold true during a temporal + // regime during which only block splits were updating the BOT. + void set_remainder_to_point_to_start(HeapWord* start, HeapWord* end, bool reducing = false); // Same as above, except that the args here are a card _index_ interval // that is closed: [start_index, end_index] - void set_remainder_to_point_to_start_incl(size_t start, size_t end); + void set_remainder_to_point_to_start_incl(size_t start, size_t end, bool reducing = false); // A helper function for BOT adjustment/verification work - void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action); + void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action, bool reducing = false); public: // The space may not have its bottom and top set yet, which is why the @@ -303,7 +332,7 @@ class BlockOffsetArray: public BlockOffsetTable { // elements of the array are initialized to zero. Otherwise, they are // initialized to point backwards to the beginning. BlockOffsetArray(BlockOffsetSharedArray* array, MemRegion mr, - bool init_to_zero); + bool init_to_zero_); // Note: this ought to be part of the constructor, but that would require // "this" to be passed as a parameter to a member constructor for @@ -358,6 +387,12 @@ class BlockOffsetArray: public BlockOffsetTable { // If true, initialize array slots with no allocated blocks to zero. // Otherwise, make them point back to the front. bool init_to_zero() { return _init_to_zero; } + // Corresponding setter + void set_init_to_zero(bool val) { + _init_to_zero = val; + assert(_array != NULL, "_array should be non-NULL"); + _array->set_init_to_zero(val); + } // Debugging // Return the index of the last entry in the "active" region. @@ -424,16 +459,16 @@ class BlockOffsetArrayNonContigSpace: public BlockOffsetArray { // of BOT is touched. It is assumed (and verified in the // non-product VM) that the remaining cards of the block // are correct. - void mark_block(HeapWord* blk_start, HeapWord* blk_end); - void mark_block(HeapWord* blk, size_t size) { - mark_block(blk, blk + size); + void mark_block(HeapWord* blk_start, HeapWord* blk_end, bool reducing = false); + void mark_block(HeapWord* blk, size_t size, bool reducing = false) { + mark_block(blk, blk + size, reducing); } // Adjust _unallocated_block to indicate that a particular // block has been newly allocated or freed. It is assumed (and // verified in the non-product VM) that the BOT is correct for // the given block. - void allocated(HeapWord* blk_start, HeapWord* blk_end) { + void allocated(HeapWord* blk_start, HeapWord* blk_end, bool reducing = false) { // Verify that the BOT shows [blk, blk + blk_size) to be one block. verify_single_block(blk_start, blk_end); if (BlockOffsetArrayUseUnallocatedBlock) { @@ -441,14 +476,12 @@ class BlockOffsetArrayNonContigSpace: public BlockOffsetArray { } } - void allocated(HeapWord* blk, size_t size) { - allocated(blk, blk + size); + void allocated(HeapWord* blk, size_t size, bool reducing = false) { + allocated(blk, blk + size, reducing); } void freed(HeapWord* blk_start, HeapWord* blk_end); - void freed(HeapWord* blk, size_t size) { - freed(blk, blk + size); - } + void freed(HeapWord* blk, size_t size); HeapWord* block_start_unsafe(const void* addr) const; @@ -456,7 +489,6 @@ class BlockOffsetArrayNonContigSpace: public BlockOffsetArray { // start of the block that contains the given address. HeapWord* block_start_careful(const void* addr) const; - // Verification & debugging: ensure that the offset table reflects // the fact that the block [blk_start, blk_end) or [blk, blk + size) // is a single block of storage. NOTE: can't const this because of diff --git a/hotspot/src/share/vm/memory/blockOffsetTable.inline.hpp b/hotspot/src/share/vm/memory/blockOffsetTable.inline.hpp index e9bee7907c3..39afcea87da 100644 --- a/hotspot/src/share/vm/memory/blockOffsetTable.inline.hpp +++ b/hotspot/src/share/vm/memory/blockOffsetTable.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,10 +55,22 @@ inline HeapWord* BlockOffsetSharedArray::address_for_index(size_t index) const { return result; } +inline void BlockOffsetSharedArray::check_reducing_assertion(bool reducing) { + assert(reducing || !SafepointSynchronize::is_at_safepoint() || init_to_zero() || + Thread::current()->is_VM_thread() || + Thread::current()->is_ConcurrentGC_thread() || + ((!Thread::current()->is_ConcurrentGC_thread()) && + ParGCRareEvent_lock->owned_by_self()), "Crack"); +} ////////////////////////////////////////////////////////////////////////// // BlockOffsetArrayNonContigSpace inlines ////////////////////////////////////////////////////////////////////////// +inline void BlockOffsetArrayNonContigSpace::freed(HeapWord* blk, + size_t size) { + freed(blk, blk + size); +} + inline void BlockOffsetArrayNonContigSpace::freed(HeapWord* blk_start, HeapWord* blk_end) { // Verify that the BOT shows [blk_start, blk_end) to be one block. diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index b8e4ab35df6..c6b8e3875e4 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -32,7 +32,11 @@ void CollectorPolicy::initialize_flags() { MaxPermSize = PermSize; } PermSize = MAX2(min_alignment(), align_size_down_(PermSize, min_alignment())); - MaxPermSize = align_size_up(MaxPermSize, max_alignment()); + // Don't increase Perm size limit above specified. + MaxPermSize = align_size_down(MaxPermSize, max_alignment()); + if (PermSize > MaxPermSize) { + PermSize = MaxPermSize; + } MinPermHeapExpansion = MAX2(min_alignment(), align_size_down_(MinPermHeapExpansion, min_alignment())); MaxPermHeapExpansion = MAX2(min_alignment(), align_size_down_(MaxPermHeapExpansion, min_alignment())); diff --git a/hotspot/src/share/vm/memory/referenceProcessor.hpp b/hotspot/src/share/vm/memory/referenceProcessor.hpp index c9966e438bd..56cf8e4d491 100644 --- a/hotspot/src/share/vm/memory/referenceProcessor.hpp +++ b/hotspot/src/share/vm/memory/referenceProcessor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -346,7 +346,8 @@ class NoRefDiscovery: StackObj { bool _was_discovering_refs; public: NoRefDiscovery(ReferenceProcessor* rp) : _rp(rp) { - if (_was_discovering_refs = _rp->discovery_enabled()) { + _was_discovering_refs = _rp->discovery_enabled(); + if (_was_discovering_refs) { _rp->disable_discovery(); } } diff --git a/hotspot/src/share/vm/oops/arrayKlassKlass.cpp b/hotspot/src/share/vm/oops/arrayKlassKlass.cpp index 2128f61f93e..b4b37b3ef1e 100644 --- a/hotspot/src/share/vm/oops/arrayKlassKlass.cpp +++ b/hotspot/src/share/vm/oops/arrayKlassKlass.cpp @@ -108,10 +108,6 @@ int arrayKlassKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { } #ifndef SERIALGC -void arrayKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert(obj->blueprint()->oop_is_arrayKlass(),"must be an array klass"); -} - void arrayKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->blueprint()->oop_is_arrayKlass(),"must be an array klass"); } diff --git a/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp b/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp index 800b7eba9b1..035d86e33d3 100644 --- a/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp +++ b/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp @@ -120,10 +120,6 @@ int compiledICHolderKlass::oop_adjust_pointers(oop obj) { } #ifndef SERIALGC -void compiledICHolderKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert(obj->is_compiledICHolder(), "must be compiledICHolder"); -} - void compiledICHolderKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_compiledICHolder(), "must be compiledICHolder"); } diff --git a/hotspot/src/share/vm/oops/constMethodKlass.cpp b/hotspot/src/share/vm/oops/constMethodKlass.cpp index b5f15e5f6b7..114dea85b6c 100644 --- a/hotspot/src/share/vm/oops/constMethodKlass.cpp +++ b/hotspot/src/share/vm/oops/constMethodKlass.cpp @@ -157,10 +157,6 @@ int constMethodKlass::oop_adjust_pointers(oop obj) { } #ifndef SERIALGC -void constMethodKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert(obj->is_constMethod(), "should be constMethod"); -} - void constMethodKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_constMethod(), "should be constMethod"); } diff --git a/hotspot/src/share/vm/oops/constantPoolKlass.cpp b/hotspot/src/share/vm/oops/constantPoolKlass.cpp index 7ca3c79b1da..656ce16b659 100644 --- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp +++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp @@ -268,21 +268,6 @@ constantPoolKlass::oop_update_pointers(ParCompactionManager* cm, oop obj, return cp->object_size(); } -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; diff --git a/hotspot/src/share/vm/oops/constantPoolOop.cpp b/hotspot/src/share/vm/oops/constantPoolOop.cpp index 62e2f64dc79..10976aab6a9 100644 --- a/hotspot/src/share/vm/oops/constantPoolOop.cpp +++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp @@ -466,6 +466,7 @@ oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, i bool ignore_is_on_bcp = false; Handle value = SystemDictionary::find_method_handle_type(signature, klass, + false, ignore_is_on_bcp, CHECK_NULL); result_oop = value(); diff --git a/hotspot/src/share/vm/oops/cpCacheKlass.cpp b/hotspot/src/share/vm/oops/cpCacheKlass.cpp index 3d7916ffaa5..216c62ee4f8 100644 --- a/hotspot/src/share/vm/oops/cpCacheKlass.cpp +++ b/hotspot/src/share/vm/oops/cpCacheKlass.cpp @@ -166,29 +166,6 @@ bool constantPoolCacheKlass::oop_is_conc_safe(oop obj) const { } #ifndef SERIALGC -void constantPoolCacheKlass::oop_copy_contents(PSPromotionManager* pm, - oop obj) { - assert(obj->is_constantPoolCache(), "should be constant pool"); - if (EnableInvokeDynamic) { - constantPoolCacheOop cache = (constantPoolCacheOop)obj; - // during a scavenge, it is safe to inspect my pool, since it is perm - constantPoolOop pool = cache->constant_pool(); - assert(pool->is_constantPool(), "should be constant pool"); - if (pool->has_invokedynamic()) { - for (int i = 0; i < cache->length(); i++) { - ConstantPoolCacheEntry* e = cache->entry_at(i); - oop* p = (oop*)&e->_f1; - if (e->is_secondary_entry()) { - if (PSScavenge::should_scavenge(p)) - pm->claim_or_forward_breadth(p); - assert(!(e->is_vfinal() && PSScavenge::should_scavenge((oop*)&e->_f2)), - "no live oops here"); - } - } - } - } -} - void constantPoolCacheKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_constantPoolCache(), "should be constant pool"); diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 87bbddc5d4f..a82b711f040 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -382,7 +382,7 @@ void instanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { const char* desc = "Could not initialize class "; const char* className = this_oop->external_name(); size_t msglen = strlen(desc) + strlen(className) + 1; - char* message = NEW_C_HEAP_ARRAY(char, msglen); + char* message = NEW_RESOURCE_ARRAY(char, msglen); if (NULL == message) { // Out of memory: can't create detailed error message THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className); @@ -1809,18 +1809,7 @@ int instanceKlass::oop_adjust_pointers(oop obj) { } #ifndef SERIALGC -void instanceKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert(!pm->depth_first(), "invariant"); - InstanceKlass_OOP_MAP_REVERSE_ITERATE( \ - obj, \ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_breadth(p); \ - }, \ - assert_nothing ) -} - void instanceKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - assert(pm->depth_first(), "invariant"); InstanceKlass_OOP_MAP_REVERSE_ITERATE( \ obj, \ if (PSScavenge::should_scavenge(p)) { \ @@ -1846,18 +1835,7 @@ int instanceKlass::oop_update_pointers(ParCompactionManager* cm, oop obj, return size_helper(); } -void instanceKlass::copy_static_fields(PSPromotionManager* pm) { - assert(!pm->depth_first(), "invariant"); - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_breadth(p); \ - }, \ - assert_nothing ) -} - void instanceKlass::push_static_fields(PSPromotionManager* pm) { - assert(pm->depth_first(), "invariant"); InstanceKlass_OOP_ITERATE( \ start_of_static_fields(), static_oop_field_size(), \ if (PSScavenge::should_scavenge(p)) { \ @@ -2222,8 +2200,23 @@ void instanceKlass::add_osr_nmethod(nmethod* n) { assert(n->is_osr_method(), "wrong kind of nmethod"); n->set_osr_link(osr_nmethods_head()); set_osr_nmethods_head(n); + // Raise the highest osr level if necessary + if (TieredCompilation) { + methodOop m = n->method(); + m->set_highest_osr_comp_level(MAX2(m->highest_osr_comp_level(), n->comp_level())); + } // Remember to unlock again OsrList_lock->unlock(); + + // Get rid of the osr methods for the same bci that have lower levels. + if (TieredCompilation) { + for (int l = CompLevel_limited_profile; l < n->comp_level(); l++) { + nmethod *inv = lookup_osr_nmethod(n->method(), n->osr_entry_bci(), l, true); + if (inv != NULL && inv->is_in_use()) { + inv->make_not_entrant(); + } + } + } } @@ -2233,39 +2226,79 @@ void instanceKlass::remove_osr_nmethod(nmethod* n) { assert(n->is_osr_method(), "wrong kind of nmethod"); nmethod* last = NULL; nmethod* cur = osr_nmethods_head(); + int max_level = CompLevel_none; // Find the max comp level excluding n + methodOop m = n->method(); // Search for match while(cur != NULL && cur != n) { + if (TieredCompilation) { + // Find max level before n + max_level = MAX2(max_level, cur->comp_level()); + } last = cur; cur = cur->osr_link(); } + nmethod* next = NULL; if (cur == n) { + next = cur->osr_link(); if (last == NULL) { // Remove first element - set_osr_nmethods_head(osr_nmethods_head()->osr_link()); + set_osr_nmethods_head(next); } else { - last->set_osr_link(cur->osr_link()); + last->set_osr_link(next); } } n->set_osr_link(NULL); + if (TieredCompilation) { + cur = next; + while (cur != NULL) { + // Find max level after n + max_level = MAX2(max_level, cur->comp_level()); + cur = cur->osr_link(); + } + m->set_highest_osr_comp_level(max_level); + } // Remember to unlock again OsrList_lock->unlock(); } -nmethod* instanceKlass::lookup_osr_nmethod(const methodOop m, int bci) const { +nmethod* instanceKlass::lookup_osr_nmethod(const methodOop m, int bci, int comp_level, bool match_level) const { // This is a short non-blocking critical region, so the no safepoint check is ok. OsrList_lock->lock_without_safepoint_check(); nmethod* osr = osr_nmethods_head(); + nmethod* best = NULL; while (osr != NULL) { assert(osr->is_osr_method(), "wrong kind of nmethod found in chain"); + // There can be a time when a c1 osr method exists but we are waiting + // for a c2 version. When c2 completes its osr nmethod we will trash + // the c1 version and only be able to find the c2 version. However + // while we overflow in the c1 code at back branches we don't want to + // try and switch to the same code as we are already running + if (osr->method() == m && (bci == InvocationEntryBci || osr->osr_entry_bci() == bci)) { - // Found a match - return it. - OsrList_lock->unlock(); - return osr; + if (match_level) { + if (osr->comp_level() == comp_level) { + // Found a match - return it. + OsrList_lock->unlock(); + return osr; + } + } else { + if (best == NULL || (osr->comp_level() > best->comp_level())) { + if (osr->comp_level() == CompLevel_highest_tier) { + // Found the best possible - return it. + OsrList_lock->unlock(); + return osr; + } + best = osr; + } + } } osr = osr->osr_link(); } OsrList_lock->unlock(); + if (best != NULL && best->comp_level() >= comp_level && match_level == false) { + return best; + } return NULL; } diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index c25b84a36eb..234e4830ad7 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -588,7 +588,7 @@ class instanceKlass: public Klass { void set_osr_nmethods_head(nmethod* h) { _osr_nmethods_head = h; }; void add_osr_nmethod(nmethod* n); void remove_osr_nmethod(nmethod* n); - nmethod* lookup_osr_nmethod(const methodOop m, int bci) const; + nmethod* lookup_osr_nmethod(const methodOop m, int bci, int level, bool match_level) const; // Breakpoint support (see methods on methodOop for details) BreakpointInfo* breakpoints() const { return _breakpoints; }; @@ -711,7 +711,6 @@ class instanceKlass: public Klass { #ifndef SERIALGC // Parallel Scavenge - void copy_static_fields(PSPromotionManager* pm); void push_static_fields(PSPromotionManager* pm); // Parallel Old diff --git a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp index 4184ce029bf..74268925ee5 100644 --- a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp @@ -292,41 +292,7 @@ int instanceKlassKlass::oop_adjust_pointers(oop obj) { } #ifndef SERIALGC -void instanceKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert(!pm->depth_first(), "invariant"); - instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->copy_static_fields(pm); - - oop* loader_addr = ik->adr_class_loader(); - if (PSScavenge::should_scavenge(loader_addr)) { - pm->claim_or_forward_breadth(loader_addr); - } - - oop* pd_addr = ik->adr_protection_domain(); - if (PSScavenge::should_scavenge(pd_addr)) { - 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); - } - - oop* bsm_addr = ik->adr_bootstrap_method(); - if (PSScavenge::should_scavenge(bsm_addr)) { - pm->claim_or_forward_breadth(bsm_addr); - } - - klassKlass::oop_copy_contents(pm, obj); -} - void instanceKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - assert(pm->depth_first(), "invariant"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); ik->push_static_fields(pm); @@ -355,7 +321,7 @@ void instanceKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { pm->claim_or_forward_depth(bsm_addr); } - klassKlass::oop_copy_contents(pm, obj); + klassKlass::oop_push_contents(pm, obj); } int instanceKlassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.cpp b/hotspot/src/share/vm/oops/instanceRefKlass.cpp index f8670f99266..022827f309f 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp @@ -272,42 +272,9 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m) #ifndef SERIALGC -template -void specialized_oop_copy_contents(instanceRefKlass *ref, - PSPromotionManager* pm, oop obj) { - assert(!pm->depth_first(), "invariant"); - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); - if (PSScavenge::should_scavenge(referent_addr)) { - ReferenceProcessor* rp = PSScavenge::reference_processor(); - if (rp->discover_reference(obj, ref->reference_type())) { - // reference already enqueued, referent and next will be traversed later - ref->instanceKlass::oop_copy_contents(pm, obj); - return; - } else { - // treat referent as normal oop - pm->claim_or_forward_breadth(referent_addr); - } - } - // treat next as normal oop - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - if (PSScavenge::should_scavenge(next_addr)) { - pm->claim_or_forward_breadth(next_addr); - } - ref->instanceKlass::oop_copy_contents(pm, obj); -} - -void instanceRefKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - if (UseCompressedOops) { - specialized_oop_copy_contents(this, pm, obj); - } else { - specialized_oop_copy_contents(this, pm, obj); - } -} - template void specialized_oop_push_contents(instanceRefKlass *ref, PSPromotionManager* pm, oop obj) { - assert(pm->depth_first(), "invariant"); T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); if (PSScavenge::should_scavenge(referent_addr)) { ReferenceProcessor* rp = PSScavenge::reference_processor(); diff --git a/hotspot/src/share/vm/oops/klassKlass.cpp b/hotspot/src/share/vm/oops/klassKlass.cpp index 74a352fda35..b1f0225d741 100644 --- a/hotspot/src/share/vm/oops/klassKlass.cpp +++ b/hotspot/src/share/vm/oops/klassKlass.cpp @@ -161,9 +161,6 @@ int klassKlass::oop_adjust_pointers(oop obj) { } #ifndef SERIALGC -void klassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { -} - void klassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { } diff --git a/hotspot/src/share/vm/oops/klassPS.hpp b/hotspot/src/share/vm/oops/klassPS.hpp index c53abf770c2..6c02905db9b 100644 --- a/hotspot/src/share/vm/oops/klassPS.hpp +++ b/hotspot/src/share/vm/oops/klassPS.hpp @@ -28,7 +28,6 @@ #ifndef SERIALGC #define PARALLEL_GC_DECLS \ - virtual void oop_copy_contents(PSPromotionManager* pm, oop obj); \ virtual void oop_push_contents(PSPromotionManager* pm, oop obj); \ /* Parallel Old GC support \ \ @@ -43,7 +42,6 @@ // Pure virtual version for klass.hpp #define PARALLEL_GC_DECLS_PV \ - virtual void oop_copy_contents(PSPromotionManager* pm, oop obj) = 0; \ virtual void oop_push_contents(PSPromotionManager* pm, oop obj) = 0; \ virtual void oop_follow_contents(ParCompactionManager* cm, oop obj) = 0; \ virtual int oop_update_pointers(ParCompactionManager* cm, oop obj) = 0; \ diff --git a/hotspot/src/share/vm/oops/methodDataKlass.cpp b/hotspot/src/share/vm/oops/methodDataKlass.cpp index 03b5bd8878b..e11f6afd6a0 100644 --- a/hotspot/src/share/vm/oops/methodDataKlass.cpp +++ b/hotspot/src/share/vm/oops/methodDataKlass.cpp @@ -154,13 +154,6 @@ int methodDataKlass::oop_adjust_pointers(oop obj) { #ifndef SERIALGC -void methodDataKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert (obj->is_methodData(), "object must be method data"); - methodDataOop m = methodDataOop(obj); - // This should never point into the young gen. - assert(!PSScavenge::should_scavenge(m->adr_method()), "Sanity"); -} - void methodDataKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert (obj->is_methodData(), "object must be method data"); methodDataOop m = methodDataOop(obj); diff --git a/hotspot/src/share/vm/oops/methodDataOop.cpp b/hotspot/src/share/vm/oops/methodDataOop.cpp index ce40af19dcc..3de63339a70 100644 --- a/hotspot/src/share/vm/oops/methodDataOop.cpp +++ b/hotspot/src/share/vm/oops/methodDataOop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -283,11 +283,17 @@ void ReceiverTypeData::print_receiver_data_on(outputStream* st) { if (receiver(row) != NULL) entries++; } st->print_cr("count(%u) entries(%u)", count(), entries); + int total = count(); + for (row = 0; row < row_limit(); row++) { + if (receiver(row) != NULL) { + total += receiver_count(row); + } + } for (row = 0; row < row_limit(); row++) { if (receiver(row) != NULL) { tab(st); receiver(row)->print_value_on(st); - st->print_cr("(%u)", receiver_count(row)); + st->print_cr("(%u %4.2f)", receiver_count(row), (float) receiver_count(row) / (float) total); } } } @@ -743,9 +749,18 @@ void methodDataOopDesc::post_initialize(BytecodeStream* stream) { // Initialize the methodDataOop corresponding to a given method. void methodDataOopDesc::initialize(methodHandle method) { ResourceMark rm; - // Set the method back-pointer. _method = method(); + + if (TieredCompilation) { + _invocation_counter.init(); + _backedge_counter.init(); + _num_loops = 0; + _num_blocks = 0; + _highest_comp_level = 0; + _highest_osr_comp_level = 0; + _would_profile = false; + } set_creation_mileage(mileage_of(method())); // Initialize flags and trap history. @@ -798,32 +813,25 @@ void methodDataOopDesc::initialize(methodHandle method) { // Get a measure of how much mileage the method has on it. int methodDataOopDesc::mileage_of(methodOop method) { int mileage = 0; - int iic = method->interpreter_invocation_count(); - if (mileage < iic) mileage = iic; - - InvocationCounter* ic = method->invocation_counter(); - InvocationCounter* bc = method->backedge_counter(); - - int icval = ic->count(); - if (ic->carry()) icval += CompileThreshold; - if (mileage < icval) mileage = icval; - int bcval = bc->count(); - if (bc->carry()) bcval += CompileThreshold; - if (mileage < bcval) mileage = bcval; + if (TieredCompilation) { + mileage = MAX2(method->invocation_count(), method->backedge_count()); + } else { + int iic = method->interpreter_invocation_count(); + if (mileage < iic) mileage = iic; + InvocationCounter* ic = method->invocation_counter(); + InvocationCounter* bc = method->backedge_counter(); + int icval = ic->count(); + if (ic->carry()) icval += CompileThreshold; + if (mileage < icval) mileage = icval; + int bcval = bc->count(); + if (bc->carry()) bcval += CompileThreshold; + if (mileage < bcval) mileage = bcval; + } return mileage; } bool methodDataOopDesc::is_mature() const { - uint current = mileage_of(_method); - uint initial = creation_mileage(); - if (current < initial) - return true; // some sort of overflow - uint target; - if (ProfileMaturityPercentage <= 0) - target = (uint) -ProfileMaturityPercentage; // absolute value - else - target = (uint)( (ProfileMaturityPercentage * CompileThreshold) / 100 ); - return (current >= initial + target); + return CompilationPolicy::policy()->is_mature(_method); } // Translate a bci to its corresponding data index (di). diff --git a/hotspot/src/share/vm/oops/methodDataOop.hpp b/hotspot/src/share/vm/oops/methodDataOop.hpp index cced93724ae..71daacb4c00 100644 --- a/hotspot/src/share/vm/oops/methodDataOop.hpp +++ b/hotspot/src/share/vm/oops/methodDataOop.hpp @@ -1206,7 +1206,25 @@ private: intx _arg_stack; // bit set of stack-allocatable arguments intx _arg_returned; // bit set of returned arguments - int _creation_mileage; // method mileage at MDO creation + int _creation_mileage; // method mileage at MDO creation + + // How many invocations has this MDO seen? + // These counters are used to determine the exact age of MDO. + // We need those because in tiered a method can be concurrently + // executed at different levels. + InvocationCounter _invocation_counter; + // Same for backedges. + InvocationCounter _backedge_counter; + // Number of loops and blocks is computed when compiling the first + // time with C1. It is used to determine if method is trivial. + short _num_loops; + short _num_blocks; + // Highest compile level this method has ever seen. + u1 _highest_comp_level; + // Same for OSR level + u1 _highest_osr_comp_level; + // Does this method contain anything worth profiling? + bool _would_profile; // Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size; @@ -1292,6 +1310,36 @@ public: int creation_mileage() const { return _creation_mileage; } void set_creation_mileage(int x) { _creation_mileage = x; } + + int invocation_count() { + if (invocation_counter()->carry()) { + return InvocationCounter::count_limit; + } + return invocation_counter()->count(); + } + int backedge_count() { + if (backedge_counter()->carry()) { + return InvocationCounter::count_limit; + } + return backedge_counter()->count(); + } + + InvocationCounter* invocation_counter() { return &_invocation_counter; } + InvocationCounter* backedge_counter() { return &_backedge_counter; } + + void set_would_profile(bool p) { _would_profile = p; } + bool would_profile() const { return _would_profile; } + + int highest_comp_level() { return _highest_comp_level; } + void set_highest_comp_level(int level) { _highest_comp_level = level; } + int highest_osr_comp_level() { return _highest_osr_comp_level; } + void set_highest_osr_comp_level(int level) { _highest_osr_comp_level = level; } + + int num_loops() const { return _num_loops; } + void set_num_loops(int n) { _num_loops = n; } + int num_blocks() const { return _num_blocks; } + void set_num_blocks(int n) { _num_blocks = n; } + bool is_mature() const; // consult mileage and ProfileMaturityPercentage static int mileage_of(methodOop m); @@ -1413,7 +1461,7 @@ public: void inc_decompile_count() { _nof_decompiles += 1; if (decompile_count() > (uint)PerMethodRecompilationCutoff) { - method()->set_not_compilable(); + method()->set_not_compilable(CompLevel_full_optimization); } } @@ -1422,6 +1470,13 @@ public: return byte_offset_of(methodDataOopDesc, _data[0]); } + static ByteSize invocation_counter_offset() { + return byte_offset_of(methodDataOopDesc, _invocation_counter); + } + static ByteSize backedge_counter_offset() { + return byte_offset_of(methodDataOopDesc, _backedge_counter); + } + // GC support oop* adr_method() const { return (oop*)&_method; } bool object_is_parsable() const { return _size != 0; } diff --git a/hotspot/src/share/vm/oops/methodKlass.cpp b/hotspot/src/share/vm/oops/methodKlass.cpp index f0ba4ad8413..29e772eed77 100644 --- a/hotspot/src/share/vm/oops/methodKlass.cpp +++ b/hotspot/src/share/vm/oops/methodKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,6 @@ methodOop methodKlass::allocate(constMethodHandle xconst, // Fix and bury in methodOop m->set_interpreter_entry(NULL); // sets i2i entry and from_int - m->set_highest_tier_compile(CompLevel_none); m->set_adapter_entry(NULL); m->clear_code(); // from_c/from_i get set to c2i/i2i @@ -89,6 +88,7 @@ methodOop methodKlass::allocate(constMethodHandle xconst, m->invocation_counter()->init(); m->backedge_counter()->init(); m->clear_number_of_breakpoints(); + assert(m->is_parsable(), "must be parsable here."); assert(m->size() == size, "wrong size for object"); // We should not publish an uprasable object's reference @@ -184,10 +184,6 @@ int methodKlass::oop_adjust_pointers(oop obj) { } #ifndef SERIALGC -void methodKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert(obj->is_method(), "should be method"); -} - void methodKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_method(), "should be method"); } @@ -250,8 +246,8 @@ void methodKlass::oop_print_on(oop obj, outputStream* st) { st->print_cr(" - method size: %d", m->method_size()); if (m->intrinsic_id() != vmIntrinsics::_none) st->print_cr(" - intrinsic id: %d %s", m->intrinsic_id(), vmIntrinsics::name_at(m->intrinsic_id())); - if (m->highest_tier_compile() != CompLevel_none) - st->print_cr(" - highest tier: %d", m->highest_tier_compile()); + if (m->highest_comp_level() != CompLevel_none) + st->print_cr(" - highest level: %d", m->highest_comp_level()); st->print_cr(" - vtable index: %d", m->_vtable_index); st->print_cr(" - i2i entry: " INTPTR_FORMAT, m->interpreter_entry()); st->print_cr(" - adapter: " INTPTR_FORMAT, m->adapter()); diff --git a/hotspot/src/share/vm/oops/methodOop.cpp b/hotspot/src/share/vm/oops/methodOop.cpp index 32032c0022c..353a5f6762f 100644 --- a/hotspot/src/share/vm/oops/methodOop.cpp +++ b/hotspot/src/share/vm/oops/methodOop.cpp @@ -233,7 +233,7 @@ void methodOopDesc::remove_unshareable_info() { } -bool methodOopDesc::was_executed_more_than(int n) const { +bool methodOopDesc::was_executed_more_than(int n) { // Invocation counter is reset when the methodOop is compiled. // If the method has compiled code we therefore assume it has // be excuted more than n times. @@ -241,7 +241,8 @@ bool methodOopDesc::was_executed_more_than(int n) const { // interpreter doesn't bump invocation counter of trivial methods // compiler does not bump invocation counter of compiled methods return true; - } else if (_invocation_counter.carry()) { + } + else if (_invocation_counter.carry() || (method_data() != NULL && method_data()->invocation_counter()->carry())) { // The carry bit is set when the counter overflows and causes // a compilation to occur. We don't know how many times // the counter has been reset, so we simply assume it has @@ -253,7 +254,7 @@ bool methodOopDesc::was_executed_more_than(int n) const { } #ifndef PRODUCT -void methodOopDesc::print_invocation_count() const { +void methodOopDesc::print_invocation_count() { if (is_static()) tty->print("static "); if (is_final()) tty->print("final "); if (is_synchronized()) tty->print("synchronized "); @@ -574,16 +575,19 @@ bool methodOopDesc::is_not_compilable(int comp_level) const { // compilers must recognize this method specially, or not at all return true; } - -#ifdef COMPILER2 - if (is_tier1_compile(comp_level)) { - if (is_not_tier1_compilable()) { - return true; - } + if (number_of_breakpoints() > 0) { + return true; } -#endif // COMPILER2 - return (_invocation_counter.state() == InvocationCounter::wait_for_nothing) - || (number_of_breakpoints() > 0); + if (comp_level == CompLevel_any) { + return is_not_c1_compilable() || is_not_c2_compilable(); + } + if (is_c1_compile(comp_level)) { + return is_not_c1_compilable(); + } + if (is_c2_compile(comp_level)) { + return is_not_c2_compilable(); + } + return false; } // call this when compiler finds that this method is not compilable @@ -604,15 +608,18 @@ void methodOopDesc::set_not_compilable(int comp_level, bool report) { xtty->stamp(); xtty->end_elem(); } -#ifdef COMPILER2 - if (is_tier1_compile(comp_level)) { - set_not_tier1_compilable(); - return; + if (comp_level == CompLevel_all) { + set_not_c1_compilable(); + set_not_c2_compilable(); + } else { + if (is_c1_compile(comp_level)) { + set_not_c1_compilable(); + } else + if (is_c2_compile(comp_level)) { + set_not_c2_compilable(); + } } -#endif /* COMPILER2 */ - assert(comp_level == CompLevel_highest_tier, "unexpected compilation level"); - invocation_counter()->set_state(InvocationCounter::wait_for_nothing); - backedge_counter()->set_state(InvocationCounter::wait_for_nothing); + CompilationPolicy::policy()->disable_compilation(this); } // Revert to using the interpreter and clear out the nmethod @@ -649,7 +656,6 @@ void methodOopDesc::unlink_method() { set_method_data(NULL); set_interpreter_throwout_count(0); set_interpreter_invocation_count(0); - _highest_tier_compile = CompLevel_none; } // Called when the method_holder is getting linked. Setup entrypoints so the method @@ -746,8 +752,8 @@ void methodOopDesc::set_code(methodHandle mh, nmethod *code) { int comp_level = code->comp_level(); // In theory there could be a race here. In practice it is unlikely // and not worth worrying about. - if (comp_level > mh->highest_tier_compile()) { - mh->set_highest_tier_compile(comp_level); + if (comp_level > mh->highest_comp_level()) { + mh->set_highest_comp_level(comp_level); } OrderAccess::storestore(); @@ -813,11 +819,13 @@ bool methodOopDesc::should_not_be_cached() const { bool methodOopDesc::is_method_handle_invoke_name(vmSymbols::SID name_sid) { switch (name_sid) { - case vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name): // FIXME: remove this transitional form case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name): case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name): return true; } + if (AllowTransitionalJSR292 + && name_sid == vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name)) + return true; return false; } @@ -905,12 +913,16 @@ methodHandle methodOopDesc::make_invoke_method(KlassHandle holder, m->set_signature_index(_imcp_invoke_signature); assert(is_method_handle_invoke_name(m->name()), ""); assert(m->signature() == signature(), ""); + assert(m->is_method_handle_invoke(), ""); #ifdef CC_INTERP ResultTypeFinder rtf(signature()); m->set_result_index(rtf.type()); #endif m->compute_size_of_parameters(THREAD); m->set_exception_table(Universe::the_empty_int_array()); + m->init_intrinsic_id(); + assert(m->intrinsic_id() == vmIntrinsics::_invokeExact || + m->intrinsic_id() == vmIntrinsics::_invokeGeneric, "must be an invoker"); // Finally, set up its entry points. assert(m->method_handle_type() == method_type(), ""); @@ -1023,6 +1035,7 @@ void methodOopDesc::init_intrinsic_id() { assert(_intrinsic_id == vmIntrinsics::_none, "do this just once"); const uintptr_t max_id_uint = right_n_bits((int)(sizeof(_intrinsic_id) * BitsPerByte)); assert((uintptr_t)vmIntrinsics::ID_LIMIT <= max_id_uint, "else fix size"); + assert(intrinsic_id_size_in_bytes() == sizeof(_intrinsic_id), ""); // the klass name is well-known: vmSymbols::SID klass_id = klass_id_for_intrinsics(method_holder()); @@ -1030,9 +1043,10 @@ void methodOopDesc::init_intrinsic_id() { // ditto for method and signature: vmSymbols::SID name_id = vmSymbols::find_sid(name()); - if (name_id == vmSymbols::NO_SID) return; + if (name_id == vmSymbols::NO_SID) return; vmSymbols::SID sig_id = vmSymbols::find_sid(signature()); - if (sig_id == vmSymbols::NO_SID) return; + if (klass_id != vmSymbols::VM_SYMBOL_ENUM_NAME(java_dyn_MethodHandle) + && sig_id == vmSymbols::NO_SID) return; jshort flags = access_flags().as_short(); vmIntrinsics::ID id = vmIntrinsics::find_id(klass_id, name_id, sig_id, flags); @@ -1061,10 +1075,13 @@ void methodOopDesc::init_intrinsic_id() { if (is_static() || !is_native()) break; switch (name_id) { case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name): - id = vmIntrinsics::_invokeGeneric; break; - default: - if (is_method_handle_invoke_name(name())) - id = vmIntrinsics::_invokeExact; + id = vmIntrinsics::_invokeGeneric; + break; + case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name): + id = vmIntrinsics::_invokeExact; + break; + case vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name): + if (AllowTransitionalJSR292) id = vmIntrinsics::_invokeExact; break; } break; @@ -1442,6 +1459,64 @@ void methodOopDesc::clear_all_breakpoints() { } +int methodOopDesc::invocation_count() { + if (TieredCompilation) { + const methodDataOop mdo = method_data(); + if (invocation_counter()->carry() || ((mdo != NULL) ? mdo->invocation_counter()->carry() : false)) { + return InvocationCounter::count_limit; + } else { + return invocation_counter()->count() + ((mdo != NULL) ? mdo->invocation_counter()->count() : 0); + } + } else { + return invocation_counter()->count(); + } +} + +int methodOopDesc::backedge_count() { + if (TieredCompilation) { + const methodDataOop mdo = method_data(); + if (backedge_counter()->carry() || ((mdo != NULL) ? mdo->backedge_counter()->carry() : false)) { + return InvocationCounter::count_limit; + } else { + return backedge_counter()->count() + ((mdo != NULL) ? mdo->backedge_counter()->count() : 0); + } + } else { + return backedge_counter()->count(); + } +} + +int methodOopDesc::highest_comp_level() const { + methodDataOop mdo = method_data(); + if (mdo != NULL) { + return mdo->highest_comp_level(); + } else { + return CompLevel_none; + } +} + +int methodOopDesc::highest_osr_comp_level() const { + methodDataOop mdo = method_data(); + if (mdo != NULL) { + return mdo->highest_osr_comp_level(); + } else { + return CompLevel_none; + } +} + +void methodOopDesc::set_highest_comp_level(int level) { + methodDataOop mdo = method_data(); + if (mdo != NULL) { + mdo->set_highest_comp_level(level); + } +} + +void methodOopDesc::set_highest_osr_comp_level(int level) { + methodDataOop mdo = method_data(); + if (mdo != NULL) { + mdo->set_highest_osr_comp_level(level); + } +} + BreakpointInfo::BreakpointInfo(methodOop m, int bci) { _bci = bci; _name_index = m->name_index(); diff --git a/hotspot/src/share/vm/oops/methodOop.hpp b/hotspot/src/share/vm/oops/methodOop.hpp index def8653192c..827e58f1ab7 100644 --- a/hotspot/src/share/vm/oops/methodOop.hpp +++ b/hotspot/src/share/vm/oops/methodOop.hpp @@ -62,9 +62,9 @@ // | method_size | max_stack | // | max_locals | size_of_parameters | // |------------------------------------------------------| -// | intrinsic_id, highest_tier | (unused) | +// | intrinsic_id, (unused) | throwout_count | // |------------------------------------------------------| -// | throwout_count | num_breakpoints | +// | num_breakpoints | (unused) | // |------------------------------------------------------| // | invocation_counter | // | backedge_counter | @@ -83,7 +83,6 @@ class CheckedExceptionElement; class LocalVariableTableElement; class AdapterHandlerEntry; - class methodDataOopDesc; class methodOopDesc : public oopDesc { @@ -93,7 +92,7 @@ class methodOopDesc : public oopDesc { constMethodOop _constMethod; // Method read-only data. constantPoolOop _constants; // Constant pool methodDataOop _method_data; - int _interpreter_invocation_count; // Count of times invoked + int _interpreter_invocation_count; // Count of times invoked (reused as prev_event_count in tiered) AccessFlags _access_flags; // Access flags int _vtable_index; // vtable index of this method (see VtableIndexFlag) // note: can have vtables with >2**16 elements (because of inheritance) @@ -105,11 +104,11 @@ class methodOopDesc : public oopDesc { u2 _max_locals; // Number of local variables used by this method u2 _size_of_parameters; // size of the parameter block (receiver + arguments) in words u1 _intrinsic_id; // vmSymbols::intrinsic_id (0 == _none) - u1 _highest_tier_compile; // Highest compile level this method has ever seen. u2 _interpreter_throwout_count; // Count of times method was exited via exception while interpreting u2 _number_of_breakpoints; // fullspeed debugging support InvocationCounter _invocation_counter; // Incremented before each activation of the method - used to trigger frequency-based optimizations InvocationCounter _backedge_counter; // Incremented before each backedge taken - used to trigger frequencey-based optimizations + #ifndef PRODUCT int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging) #endif @@ -221,8 +220,11 @@ class methodOopDesc : public oopDesc { // max locals int max_locals() const { return _max_locals; } void set_max_locals(int size) { _max_locals = size; } - int highest_tier_compile() { return _highest_tier_compile;} - void set_highest_tier_compile(int level) { _highest_tier_compile = level;} + + int highest_comp_level() const; + void set_highest_comp_level(int level); + int highest_osr_comp_level() const; + void set_highest_osr_comp_level(int level); // Count of times method was exited via exception while interpreting void interpreter_throwout_increment() { @@ -276,21 +278,29 @@ class methodOopDesc : public oopDesc { } // invocation counter - InvocationCounter* invocation_counter() { return &_invocation_counter; } - InvocationCounter* backedge_counter() { return &_backedge_counter; } - int invocation_count() const { return _invocation_counter.count(); } - int backedge_count() const { return _backedge_counter.count(); } - bool was_executed_more_than(int n) const; - bool was_never_executed() const { return !was_executed_more_than(0); } + InvocationCounter* invocation_counter() { return &_invocation_counter; } + InvocationCounter* backedge_counter() { return &_backedge_counter; } + + int invocation_count(); + int backedge_count(); + + bool was_executed_more_than(int n); + bool was_never_executed() { return !was_executed_more_than(0); } static void build_interpreter_method_data(methodHandle method, TRAPS); - int interpreter_invocation_count() const { return _interpreter_invocation_count; } + int interpreter_invocation_count() { + if (TieredCompilation) return invocation_count(); + else return _interpreter_invocation_count; + } void set_interpreter_invocation_count(int count) { _interpreter_invocation_count = count; } - int increment_interpreter_invocation_count() { return ++_interpreter_invocation_count; } + int increment_interpreter_invocation_count() { + if (TieredCompilation) ShouldNotReachHere(); + return ++_interpreter_invocation_count; + } #ifndef PRODUCT - int compiled_invocation_count() const { return _compiled_invocation_count; } + int compiled_invocation_count() const { return _compiled_invocation_count; } void set_compiled_invocation_count(int count) { _compiled_invocation_count = count; } #endif // not PRODUCT @@ -361,7 +371,7 @@ class methodOopDesc : public oopDesc { #ifndef PRODUCT // operations on invocation counter - void print_invocation_count() const; + void print_invocation_count(); #endif // byte codes @@ -506,6 +516,8 @@ class methodOopDesc : public oopDesc { static int method_data_offset_in_bytes() { return offset_of(methodOopDesc, _method_data); } static int interpreter_invocation_counter_offset_in_bytes() { return offset_of(methodOopDesc, _interpreter_invocation_count); } + static int intrinsic_id_offset_in_bytes() { return offset_of(methodOopDesc, _intrinsic_id); } + static int intrinsic_id_size_in_bytes() { return sizeof(u1); } // Static methods that are used to implement member methods where an exposed this pointer // is needed due to possible GCs @@ -587,8 +599,13 @@ class methodOopDesc : public oopDesc { static vmSymbols::SID klass_id_for_intrinsics(klassOop holder); // On-stack replacement support - bool has_osr_nmethod() { return instanceKlass::cast(method_holder())->lookup_osr_nmethod(this, InvocationEntryBci) != NULL; } - nmethod* lookup_osr_nmethod_for(int bci) { return instanceKlass::cast(method_holder())->lookup_osr_nmethod(this, bci); } + bool has_osr_nmethod(int level, bool match_level) { + return instanceKlass::cast(method_holder())->lookup_osr_nmethod(this, InvocationEntryBci, level, match_level) != NULL; + } + + nmethod* lookup_osr_nmethod_for(int bci, int level, bool match_level) { + return instanceKlass::cast(method_holder())->lookup_osr_nmethod(this, bci, level, match_level); + } // Inline cache support void cleanup_inline_caches(); @@ -600,22 +617,24 @@ class methodOopDesc : public oopDesc { // Indicates whether compilation failed earlier for this method, or // whether it is not compilable for another reason like having a // breakpoint set in it. - bool is_not_compilable(int comp_level = CompLevel_highest_tier) const; - void set_not_compilable(int comp_level = CompLevel_highest_tier, bool report = true); - void set_not_compilable_quietly(int comp_level = CompLevel_highest_tier) { + bool is_not_compilable(int comp_level = CompLevel_any) const; + void set_not_compilable(int comp_level = CompLevel_all, bool report = true); + void set_not_compilable_quietly(int comp_level = CompLevel_all) { set_not_compilable(comp_level, false); } - - bool is_not_osr_compilable() const { return is_not_compilable() || access_flags().is_not_osr_compilable(); } - void set_not_osr_compilable() { _access_flags.set_not_osr_compilable(); } - - bool is_not_tier1_compilable() const { return access_flags().is_not_tier1_compilable(); } - void set_not_tier1_compilable() { _access_flags.set_not_tier1_compilable(); } + bool is_not_osr_compilable(int comp_level = CompLevel_any) const { + return is_not_compilable(comp_level) || access_flags().is_not_osr_compilable(); + } + void set_not_osr_compilable() { _access_flags.set_not_osr_compilable(); } + bool is_not_c1_compilable() const { return access_flags().is_not_c1_compilable(); } + void set_not_c1_compilable() { _access_flags.set_not_c1_compilable(); } + bool is_not_c2_compilable() const { return access_flags().is_not_c2_compilable(); } + void set_not_c2_compilable() { _access_flags.set_not_c2_compilable(); } // Background compilation support - bool queued_for_compilation() const { return access_flags().queued_for_compilation(); } - void set_queued_for_compilation() { _access_flags.set_queued_for_compilation(); } - void clear_queued_for_compilation() { _access_flags.clear_queued_for_compilation(); } + bool queued_for_compilation() const { return access_flags().queued_for_compilation(); } + void set_queued_for_compilation() { _access_flags.set_queued_for_compilation(); } + void clear_queued_for_compilation() { _access_flags.clear_queued_for_compilation(); } static methodOop method_from_bcp(address bcp); diff --git a/hotspot/src/share/vm/oops/objArrayKlass.cpp b/hotspot/src/share/vm/oops/objArrayKlass.cpp index 96935b61448..a932a117d67 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp @@ -426,18 +426,7 @@ int objArrayKlass::oop_adjust_pointers(oop obj) { } #ifndef SERIALGC -void objArrayKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert(!pm->depth_first(), "invariant"); - assert(obj->is_objArray(), "obj must be obj array"); - ObjArrayKlass_OOP_ITERATE( \ - objArrayOop(obj), p, \ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_breadth(p); \ - }) -} - void objArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - assert(pm->depth_first(), "invariant"); assert(obj->is_objArray(), "obj must be obj array"); ObjArrayKlass_OOP_ITERATE( \ objArrayOop(obj), p, \ diff --git a/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp b/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp index f486dc7db40..7050d57b14b 100644 --- a/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp +++ b/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp @@ -229,10 +229,6 @@ objArrayKlassKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { } #ifndef SERIALGC -void objArrayKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert(obj->blueprint()->oop_is_objArrayKlass(),"must be an obj array klass"); -} - void objArrayKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->blueprint()->oop_is_objArrayKlass(),"must be an obj array klass"); } diff --git a/hotspot/src/share/vm/oops/oop.hpp b/hotspot/src/share/vm/oops/oop.hpp index 952802c7801..04d31180401 100644 --- a/hotspot/src/share/vm/oops/oop.hpp +++ b/hotspot/src/share/vm/oops/oop.hpp @@ -306,7 +306,6 @@ class oopDesc { #ifndef SERIALGC // Parallel Scavenge - void copy_contents(PSPromotionManager* pm); void push_contents(PSPromotionManager* pm); // Parallel Old diff --git a/hotspot/src/share/vm/oops/oop.psgc.inline.hpp b/hotspot/src/share/vm/oops/oop.psgc.inline.hpp index 07ad5c5a653..40d40a3725b 100644 --- a/hotspot/src/share/vm/oops/oop.psgc.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.psgc.inline.hpp @@ -24,15 +24,6 @@ // ParallelScavengeHeap methods -inline void oopDesc::copy_contents(PSPromotionManager* pm) { - Klass* klass = blueprint(); - if (!klass->oop_is_typeArray()) { - // It might contain oops beyond the header, so take the virtual call. - klass->oop_copy_contents(pm, this); - } - // Else skip it. The typeArrayKlass in the header never needs scavenging. -} - inline void oopDesc::push_contents(PSPromotionManager* pm) { Klass* klass = blueprint(); if (!klass->oop_is_typeArray()) { diff --git a/hotspot/src/share/vm/oops/symbolKlass.cpp b/hotspot/src/share/vm/oops/symbolKlass.cpp index 4fe4dc86090..e3806db1202 100644 --- a/hotspot/src/share/vm/oops/symbolKlass.cpp +++ b/hotspot/src/share/vm/oops/symbolKlass.cpp @@ -184,10 +184,6 @@ int symbolKlass::oop_adjust_pointers(oop obj) { #ifndef SERIALGC -void symbolKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert(obj->is_symbol(), "should be symbol"); -} - void symbolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_symbol(), "should be symbol"); } diff --git a/hotspot/src/share/vm/oops/typeArrayKlass.cpp b/hotspot/src/share/vm/oops/typeArrayKlass.cpp index edb216e68ae..088960ce0b6 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp @@ -228,10 +228,6 @@ int typeArrayKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { } #ifndef SERIALGC -void typeArrayKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { - assert(obj->is_typeArray(),"must be a type array"); -} - void typeArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_typeArray(),"must be a type array"); } diff --git a/hotspot/src/share/vm/opto/addnode.cpp b/hotspot/src/share/vm/opto/addnode.cpp index 5f2332a14f6..b6d073d5b9e 100644 --- a/hotspot/src/share/vm/opto/addnode.cpp +++ b/hotspot/src/share/vm/opto/addnode.cpp @@ -705,6 +705,9 @@ int AddPNode::unpack_offsets(Node* elements[], int length) { } addr = addr->in(AddPNode::Address); } + if (addr != base) { + return -1; + } return count; } diff --git a/hotspot/src/share/vm/opto/bytecodeInfo.cpp b/hotspot/src/share/vm/opto/bytecodeInfo.cpp index b4178384b60..ca0a3260f21 100644 --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp @@ -140,7 +140,7 @@ const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_m } else { // Not hot. Check for medium-sized pre-existing nmethod at cold sites. if (callee_method->has_compiled_code() && - callee_method->instructions_size() > InlineSmallCode/4) + callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode/4) return "already compiled into a medium method"; } if (size > max_size) { @@ -180,7 +180,7 @@ const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* calle } } - if (callee_method->has_compiled_code() && callee_method->instructions_size() > InlineSmallCode) { + if (callee_method->has_compiled_code() && callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode) { wci_result->set_profit(wci_result->profit() * 0.1); // %%% adjust wci_result->size()? } @@ -206,7 +206,7 @@ const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* calle // Now perform checks which are heuristic - if( callee_method->has_compiled_code() && callee_method->instructions_size() > InlineSmallCode ) + if( callee_method->has_compiled_code() && callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode ) return "already compiled into a big method"; // don't inline exception code unless the top method belongs to an diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 3fdaf842740..9b35d5be86a 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -157,6 +157,12 @@ develop(bool, TraceLoopPredicate, false, \ "Trace generation of loop predicates") \ \ + product(bool, OptimizeFill, false, \ + "convert fill/copy loops into intrinsic") \ + \ + develop(bool, TraceOptimizeFill, false, \ + "print detailed information about fill conversion") \ + \ develop(bool, OptoCoalesce, true, \ "Use Conservative Copy Coalescing in the Register Allocator") \ \ @@ -178,6 +184,9 @@ product(bool, ReduceBulkZeroing, true, \ "When bulk-initializing, try to avoid needless zeroing") \ \ + product(bool, UseFPUForSpilling, false, \ + "Spill integer registers to FPU instead of stack when possible") \ + \ develop_pd(intx, RegisterCostAreaRatio, \ "Spill selection in reg allocator: scale area by (X/64K) before " \ "adding cost") \ diff --git a/hotspot/src/share/vm/opto/coalesce.cpp b/hotspot/src/share/vm/opto/coalesce.cpp index 311b55a717f..2144b59ec3b 100644 --- a/hotspot/src/share/vm/opto/coalesce.cpp +++ b/hotspot/src/share/vm/opto/coalesce.cpp @@ -780,6 +780,14 @@ bool PhaseConservativeCoalesce::copy_copy( Node *dst_copy, Node *src_copy, Block // Number of bits free uint rm_size = rm.Size(); + if (UseFPUForSpilling && rm.is_AllStack() ) { + // Don't coalesce when frequency difference is large + Block *dst_b = _phc._cfg._bbs[dst_copy->_idx]; + Block *src_def_b = _phc._cfg._bbs[src_def->_idx]; + if (src_def_b->_freq > 10*dst_b->_freq ) + return false; + } + // If we can use any stack slot, then effective size is infinite if( rm.is_AllStack() ) rm_size += 1000000; // Incompatible masks, no way to coalesce diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index e5d3c4fdd67..7289cc2b8d7 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -400,7 +400,7 @@ void Compile::init_scratch_buffer_blob() { } // Initialize the relocation buffers - relocInfo* locs_buf = (relocInfo*) blob->instructions_end() - MAX_locs_size; + relocInfo* locs_buf = (relocInfo*) blob->content_end() - MAX_locs_size; set_scratch_locs_memory(locs_buf); } @@ -422,9 +422,9 @@ uint Compile::scratch_emit_size(const Node* n) { assert(blob != NULL, "Initialize BufferBlob at start"); assert(blob->size() > MAX_inst_size, "sanity"); relocInfo* locs_buf = scratch_locs_memory(); - address blob_begin = blob->instructions_begin(); + address blob_begin = blob->content_begin(); address blob_end = (address)locs_buf; - assert(blob->instructions_contains(blob_end), "sanity"); + assert(blob->content_contains(blob_end), "sanity"); CodeBuffer buf(blob_begin, blob_end - blob_begin); buf.initialize_consts_size(MAX_const_size); buf.initialize_stubs_size(MAX_stubs_size); @@ -433,7 +433,7 @@ uint Compile::scratch_emit_size(const Node* n) { buf.insts()->initialize_shared_locs(&locs_buf[0], lsize); buf.stubs()->initialize_shared_locs(&locs_buf[lsize], lsize); n->emit(buf, this->regalloc()); - return buf.code_size(); + return buf.insts_size(); } @@ -850,25 +850,13 @@ void Compile::Init(int aliaslevel) { 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); - set_do_inlining(Tier1Inline != 0); - set_max_inline_size(Tier1MaxInlineSize); - set_freq_inline_size(Tier1FreqInlineSize); - set_do_scheduling(false); - set_do_count_invocations(Tier1CountInvocations); - set_do_method_data_update(Tier1UpdateMethodData); - } else { - assert(env()->comp_level() == CompLevel_full_optimization, "unknown comp level"); - set_num_loop_opts(LoopOptsCount); - set_do_inlining(Inline); - set_max_inline_size(MaxInlineSize); - set_freq_inline_size(FreqInlineSize); - set_do_scheduling(OptoScheduling); - set_do_count_invocations(false); - set_do_method_data_update(false); - } + set_num_loop_opts(LoopOptsCount); + set_do_inlining(Inline); + set_max_inline_size(MaxInlineSize); + set_freq_inline_size(FreqInlineSize); + set_do_scheduling(OptoScheduling); + set_do_count_invocations(false); + set_do_method_data_update(false); if (debug_info()->recording_non_safepoints()) { set_node_note_array(new(comp_arena()) GrowableArray diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index 42a974b9b34..cbf43cb553f 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1739,6 +1739,7 @@ void GraphKit::replace_call(CallNode* call, Node* result) { C->gvn_replace_by(callprojs.fallthrough_catchproj, final_state->in(TypeFunc::Control)); C->gvn_replace_by(callprojs.fallthrough_memproj, final_state->in(TypeFunc::Memory)); C->gvn_replace_by(callprojs.fallthrough_ioproj, final_state->in(TypeFunc::I_O)); + Node* final_mem = final_state->in(TypeFunc::Memory); // Replace the result with the new result if it exists and is used if (callprojs.resproj != NULL && result != NULL) { @@ -1776,6 +1777,21 @@ void GraphKit::replace_call(CallNode* call, Node* result) { // Disconnect the call from the graph call->disconnect_inputs(NULL); C->gvn_replace_by(call, C->top()); + + // Clean up any MergeMems that feed other MergeMems since the + // optimizer doesn't like that. + if (final_mem->is_MergeMem()) { + Node_List wl; + for (SimpleDUIterator i(final_mem); i.has_next(); i.next()) { + Node* m = i.get(); + if (m->is_MergeMem() && !wl.contains(m)) { + wl.push(m); + } + } + while (wl.size() > 0) { + _gvn.transform(wl.pop()); + } + } } @@ -1891,7 +1907,7 @@ void GraphKit::uncommon_trap(int trap_request, kill_dead_locals(); // Now insert the uncommon trap subroutine call - address call_addr = SharedRuntime::uncommon_trap_blob()->instructions_begin(); + address call_addr = SharedRuntime::uncommon_trap_blob()->entry_point(); const TypePtr* no_memory_effects = NULL; // Pass the index of the class to be loaded Node* call = make_runtime_call(RC_NO_LEAF | RC_UNCOMMON | @@ -2451,11 +2467,79 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass, } +//------------------------------seems_never_null------------------------------- +// Use null_seen information if it is available from the profile. +// If we see an unexpected null at a type check we record it and force a +// recompile; the offending check will be recompiled to handle NULLs. +// If we see several offending BCIs, then all checks in the +// method will be recompiled. +bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) { + if (UncommonNullCast // Cutout for this technique + && obj != null() // And not the -Xcomp stupid case? + && !too_many_traps(Deoptimization::Reason_null_check) + ) { + if (data == NULL) + // Edge case: no mature data. Be optimistic here. + return true; + // If the profile has not seen a null, assume it won't happen. + assert(java_bc() == Bytecodes::_checkcast || + java_bc() == Bytecodes::_instanceof || + java_bc() == Bytecodes::_aastore, "MDO must collect null_seen bit here"); + return !data->as_BitData()->null_seen(); + } + return false; +} + +//------------------------maybe_cast_profiled_receiver------------------------- +// If the profile has seen exactly one type, narrow to exactly that type. +// Subsequent type checks will always fold up. +Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj, + ciProfileData* data, + ciKlass* require_klass) { + if (!UseTypeProfile || !TypeProfileCasts) return NULL; + if (data == NULL) return NULL; + + // Make sure we haven't already deoptimized from this tactic. + if (too_many_traps(Deoptimization::Reason_class_check)) + return NULL; + + // (No, this isn't a call, but it's enough like a virtual call + // to use the same ciMethod accessor to get the profile info...) + ciCallProfile profile = method()->call_profile_at_bci(bci()); + if (profile.count() >= 0 && // no cast failures here + profile.has_receiver(0) && + profile.morphism() == 1) { + ciKlass* exact_kls = profile.receiver(0); + if (require_klass == NULL || + static_subtype_check(require_klass, exact_kls) == SSC_always_true) { + // If we narrow the type to match what the type profile sees, + // we can then remove the rest of the cast. + // This is a win, even if the exact_kls is very specific, + // because downstream operations, such as method calls, + // will often benefit from the sharper type. + Node* exact_obj = not_null_obj; // will get updated in place... + Node* slow_ctl = type_check_receiver(exact_obj, exact_kls, 1.0, + &exact_obj); + { PreserveJVMState pjvms(this); + set_control(slow_ctl); + uncommon_trap(Deoptimization::Reason_class_check, + Deoptimization::Action_maybe_recompile); + } + replace_in_map(not_null_obj, exact_obj); + return exact_obj; + } + // assert(ssc == SSC_always_true)... except maybe the profile lied to us. + } + + return NULL; +} + + //-------------------------------gen_instanceof-------------------------------- // Generate an instance-of idiom. Used by both the instance-of bytecode // and the reflective instance-of call. -Node* GraphKit::gen_instanceof( Node *subobj, Node* superklass ) { - C->set_has_split_ifs(true); // Has chance for split-if optimization +Node* GraphKit::gen_instanceof(Node* obj, Node* superklass) { + kill_dead_locals(); // Benefit all the uncommon traps assert( !stopped(), "dead parse path should be checked in callers" ); assert(!TypePtr::NULL_PTR->higher_equal(_gvn.type(superklass)->is_klassptr()), "must check for not-null not-dead klass in callers"); @@ -2466,9 +2550,16 @@ Node* GraphKit::gen_instanceof( Node *subobj, Node* superklass ) { Node* phi = new(C, PATH_LIMIT) PhiNode(region, TypeInt::BOOL); C->set_has_split_ifs(true); // Has chance for split-if optimization + ciProfileData* data = NULL; + if (java_bc() == Bytecodes::_instanceof) { // Only for the bytecode + data = method()->method_data()->bci_to_data(bci()); + } + bool never_see_null = (ProfileDynamicTypes // aggressive use of profile + && seems_never_null(obj, data)); + // Null check; get casted pointer; set region slot 3 Node* null_ctl = top(); - Node* not_null_obj = null_check_oop(subobj, &null_ctl); + Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null); // If not_null_obj is dead, only null-path is taken if (stopped()) { // Doing instance-of on a NULL? @@ -2477,6 +2568,23 @@ Node* GraphKit::gen_instanceof( Node *subobj, Node* superklass ) { } region->init_req(_null_path, null_ctl); phi ->init_req(_null_path, intcon(0)); // Set null path value + if (null_ctl == top()) { + // Do this eagerly, so that pattern matches like is_diamond_phi + // will work even during parsing. + assert(_null_path == PATH_LIMIT-1, "delete last"); + region->del_req(_null_path); + phi ->del_req(_null_path); + } + + if (ProfileDynamicTypes && data != NULL) { + Node* cast_obj = maybe_cast_profiled_receiver(not_null_obj, data, NULL); + if (stopped()) { // Profile disagrees with this path. + set_control(null_ctl); // Null is the only remaining possibility. + return intcon(0); + } + if (cast_obj != NULL) + not_null_obj = cast_obj; + } // Load the object's klass Node* obj_klass = load_object_klass(not_null_obj); @@ -2546,20 +2654,8 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, C->set_has_split_ifs(true); // Has chance for split-if optimization // Use null-cast information if it is available - bool never_see_null = false; - // If we see an unexpected null at a check-cast we record it and force a - // recompile; the offending check-cast will be compiled to handle NULLs. - // If we see several offending BCIs, then all checkcasts in the - // method will be compiled to handle NULLs. - if (UncommonNullCast // Cutout for this technique - && failure_control == NULL // regular case - && obj != null() // And not the -Xcomp stupid case? - && !too_many_traps(Deoptimization::Reason_null_check)) { - // Finally, check the "null_seen" bit from the interpreter. - if (data == NULL || !data->as_BitData()->null_seen()) { - never_see_null = true; - } - } + bool never_see_null = ((failure_control == NULL) // regular case only + && seems_never_null(obj, data)); // Null check; get casted pointer; set region slot 3 Node* null_ctl = top(); @@ -2572,47 +2668,26 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, } region->init_req(_null_path, null_ctl); phi ->init_req(_null_path, null()); // Set null path value + if (null_ctl == top()) { + // Do this eagerly, so that pattern matches like is_diamond_phi + // will work even during parsing. + assert(_null_path == PATH_LIMIT-1, "delete last"); + region->del_req(_null_path); + phi ->del_req(_null_path); + } - Node* cast_obj = NULL; // the casted version of the object - - // If the profile has seen exactly one type, narrow to that type. - // (The subsequent subtype check will always fold up.) - if (UseTypeProfile && TypeProfileCasts && data != NULL && + Node* cast_obj = NULL; + if (data != NULL && // Counter has never been decremented (due to cast failure). // ...This is a reasonable thing to expect. It is true of // all casts inserted by javac to implement generic types. - data->as_CounterData()->count() >= 0 && - !too_many_traps(Deoptimization::Reason_class_check)) { - // (No, this isn't a call, but it's enough like a virtual call - // to use the same ciMethod accessor to get the profile info...) - ciCallProfile profile = method()->call_profile_at_bci(bci()); - if (profile.count() >= 0 && // no cast failures here - profile.has_receiver(0) && - profile.morphism() == 1) { - ciKlass* exact_kls = profile.receiver(0); - int ssc = static_subtype_check(tk->klass(), exact_kls); - if (ssc == SSC_always_true) { - // If we narrow the type to match what the type profile sees, - // we can then remove the rest of the cast. - // This is a win, even if the exact_kls is very specific, - // because downstream operations, such as method calls, - // will often benefit from the sharper type. - Node* exact_obj = not_null_obj; // will get updated in place... - Node* slow_ctl = type_check_receiver(exact_obj, exact_kls, 1.0, - &exact_obj); - { PreserveJVMState pjvms(this); - set_control(slow_ctl); - uncommon_trap(Deoptimization::Reason_class_check, - Deoptimization::Action_maybe_recompile); - } - if (failure_control != NULL) // failure is now impossible - (*failure_control) = top(); - replace_in_map(not_null_obj, exact_obj); - // adjust the type of the phi to the exact klass: - phi->raise_bottom_type(_gvn.type(exact_obj)->meet(TypePtr::NULL_PTR)); - cast_obj = exact_obj; - } - // assert(cast_obj != NULL)... except maybe the profile lied to us. + data->as_CounterData()->count() >= 0) { + cast_obj = maybe_cast_profiled_receiver(not_null_obj, data, tk->klass()); + if (cast_obj != NULL) { + if (failure_control != NULL) // failure is now impossible + (*failure_control) = top(); + // adjust the type of the phi to the exact klass: + phi->raise_bottom_type(_gvn.type(cast_obj)->meet(TypePtr::NULL_PTR)); } } diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index 6641f21c1d1..3d15fe826b5 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -341,6 +341,14 @@ class GraphKit : public Phase { Node* null_check_oop(Node* value, Node* *null_control, bool never_see_null = false); + // Check the null_seen bit. + bool seems_never_null(Node* obj, ciProfileData* data); + + // Use the type profile to narrow an object type. + Node* maybe_cast_profiled_receiver(Node* not_null_obj, + ciProfileData* data, + ciKlass* require_klass); + // Cast obj to not-null on this path Node* cast_not_null(Node* obj, bool do_replace_in_map = true); // Replace all occurrences of one node by another. diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index 2e43346c7e4..c93b53eb946 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,8 +72,7 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe for (uint i1 = 0; i1 < null_block->_nodes.size(); i1++) { Node* nn = null_block->_nodes[i1]; if (nn->is_MachCall() && - nn->as_MachCall()->entry_point() == - SharedRuntime::uncommon_trap_blob()->instructions_begin()) { + nn->as_MachCall()->entry_point() == SharedRuntime::uncommon_trap_blob()->entry_point()) { const Type* trtype = nn->in(TypeFunc::Parms)->bottom_type(); if (trtype->isa_int() && trtype->is_int()->is_con()) { jint tr_con = trtype->is_int()->get_con(); diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 2eb0de79ceb..f48ed6f312b 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -906,7 +906,8 @@ bool LibraryCallKit::inline_string_equals() { const int count_offset = java_lang_String::count_offset_in_bytes(); const int offset_offset = java_lang_String::offset_offset_in_bytes(); - _sp += 2; + int nargs = 2; + _sp += nargs; Node* argument = pop(); // pop non-receiver first: it was pushed second Node* receiver = pop(); @@ -914,11 +915,11 @@ bool LibraryCallKit::inline_string_equals() { // null check technically happens in the wrong place, which can lead to // invalid stack traces when string compare is inlined into a method // which handles NullPointerExceptions. - _sp += 2; + _sp += nargs; receiver = do_null_check(receiver, T_OBJECT); //should not do null check for argument for String.equals(), because spec //allows to specify NULL as argument. - _sp -= 2; + _sp -= nargs; if (stopped()) { return true; @@ -943,7 +944,9 @@ bool LibraryCallKit::inline_string_equals() { ciInstanceKlass* klass = env()->String_klass(); if (!stopped()) { + _sp += nargs; // gen_instanceof might do an uncommon trap Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass))); + _sp -= nargs; Node* cmp = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1))); Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::ne)); @@ -2935,7 +2938,9 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { switch (id) { case vmIntrinsics::_isInstance: // nothing is an instance of a primitive type + _sp += nargs; // gen_instanceof might do an uncommon trap query_value = gen_instanceof(obj, kls); + _sp -= nargs; break; case vmIntrinsics::_getModifiers: @@ -4957,8 +4962,7 @@ LibraryCallKit::tightly_coupled_allocation(Node* ptr, for (DUIterator_Fast jmax, j = not_ctl->fast_outs(jmax); j < jmax; j++) { Node* obs = not_ctl->fast_out(j); if (obs->in(0) == not_ctl && obs->is_Call() && - (obs->as_Call()->entry_point() == - SharedRuntime::uncommon_trap_blob()->instructions_begin())) { + (obs->as_Call()->entry_point() == SharedRuntime::uncommon_trap_blob()->entry_point())) { found_trap = true; break; } } diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 31daf7d8fef..2c115b12838 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -2049,11 +2049,18 @@ bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invari if (cmp->Opcode() != Op_CmpU ) { return false; } - if (cmp->in(2)->Opcode() != Op_LoadRange) { - return false; + Node* range = cmp->in(2); + if (range->Opcode() != Op_LoadRange) { + const TypeInt* tint = phase->_igvn.type(range)->isa_int(); + if (!OptimizeFill || tint == NULL || tint->empty() || tint->_lo < 0) { + // Allow predication on positive values that aren't LoadRanges. + // This allows optimization of loops where the length of the + // array is a known value and doesn't need to be loaded back + // from the array. + return false; + } } - LoadRangeNode* lr = (LoadRangeNode*)cmp->in(2); - if (!invar.is_invariant(lr)) { // loadRange must be invariant + if (!invar.is_invariant(range)) { return false; } Node *iv = _head->as_CountedLoop()->phi(); @@ -2248,9 +2255,9 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { const Node* cmp = bol->in(1)->as_Cmp(); Node* idx = cmp->in(1); assert(!invar.is_invariant(idx), "index is variant"); - assert(cmp->in(2)->Opcode() == Op_LoadRange, "must be"); - Node* ld_rng = cmp->in(2); // LoadRangeNode - assert(invar.is_invariant(ld_rng), "load range must be invariant"); + assert(cmp->in(2)->Opcode() == Op_LoadRange || OptimizeFill, "must be"); + Node* rng = cmp->in(2); + assert(invar.is_invariant(rng), "range must be invariant"); int scale = 1; Node* offset = zero; bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset); @@ -2271,21 +2278,21 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { // Perform cloning to keep Invariance state correct since the // late schedule will place invariant things in the loop. - ld_rng = invar.clone(ld_rng, ctrl); + rng = invar.clone(rng, ctrl); if (offset && offset != zero) { assert(invar.is_invariant(offset), "offset must be loop invariant"); offset = invar.clone(offset, ctrl); } // Test the lower bound - Node* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng, false); + Node* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, false); IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If(); _igvn.hash_delete(lower_bound_iff); lower_bound_iff->set_req(1, lower_bound_bol); if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx); // Test the upper bound - Node* upper_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng, true); + Node* upper_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, true); IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If(); _igvn.hash_delete(upper_bound_iff); upper_bound_iff->set_req(1, upper_bound_bol); @@ -2366,3 +2373,358 @@ bool IdealLoopTree::loop_predication( PhaseIdealLoop *phase) { return hoisted; } + + +// Process all the loops in the loop tree and replace any fill +// patterns with an intrisc version. +bool PhaseIdealLoop::do_intrinsify_fill() { + bool changed = false; + for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) { + IdealLoopTree* lpt = iter.current(); + changed |= intrinsify_fill(lpt); + } + return changed; +} + + +// Examine an inner loop looking for a a single store of an invariant +// value in a unit stride loop, +bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& store_value, + Node*& shift, Node*& con) { + const char* msg = NULL; + Node* msg_node = NULL; + + store_value = NULL; + con = NULL; + shift = NULL; + + // Process the loop looking for stores. If there are multiple + // stores or extra control flow give at this point. + CountedLoopNode* head = lpt->_head->as_CountedLoop(); + for (uint i = 0; msg == NULL && i < lpt->_body.size(); i++) { + Node* n = lpt->_body.at(i); + if (n->outcnt() == 0) continue; // Ignore dead + if (n->is_Store()) { + if (store != NULL) { + msg = "multiple stores"; + break; + } + int opc = n->Opcode(); + if (opc == Op_StoreP || opc == Op_StoreN || opc == Op_StoreCM) { + msg = "oop fills not handled"; + break; + } + Node* value = n->in(MemNode::ValueIn); + if (!lpt->is_invariant(value)) { + msg = "variant store value"; + } else if (!_igvn.type(n->in(MemNode::Address))->isa_aryptr()) { + msg = "not array address"; + } + store = n; + store_value = value; + } else if (n->is_If() && n != head->loopexit()) { + msg = "extra control flow"; + msg_node = n; + } + } + + if (store == NULL) { + // No store in loop + return false; + } + + if (msg == NULL && head->stride_con() != 1) { + // could handle negative strides too + if (head->stride_con() < 0) { + msg = "negative stride"; + } else { + msg = "non-unit stride"; + } + } + + if (msg == NULL && !store->in(MemNode::Address)->is_AddP()) { + msg = "can't handle store address"; + msg_node = store->in(MemNode::Address); + } + + // Make sure there is an appropriate fill routine + BasicType t = store->as_Mem()->memory_type(); + const char* fill_name; + if (msg == NULL && + StubRoutines::select_fill_function(t, false, fill_name) == NULL) { + msg = "unsupported store"; + msg_node = store; + } + + if (msg != NULL) { +#ifndef PRODUCT + if (TraceOptimizeFill) { + tty->print_cr("not fill intrinsic candidate: %s", msg); + if (msg_node != NULL) msg_node->dump(); + } +#endif + return false; + } + + // Make sure the address expression can be handled. It should be + // head->phi * elsize + con. head->phi might have a ConvI2L. + Node* elements[4]; + Node* conv = NULL; + bool found_index = false; + int count = store->in(MemNode::Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements)); + for (int e = 0; e < count; e++) { + Node* n = elements[e]; + if (n->is_Con() && con == NULL) { + con = n; + } else if (n->Opcode() == Op_LShiftX && shift == NULL) { + Node* value = n->in(1); +#ifdef _LP64 + if (value->Opcode() == Op_ConvI2L) { + conv = value; + value = value->in(1); + } +#endif + if (value != head->phi()) { + msg = "unhandled shift in address"; + } else { + found_index = true; + shift = n; + assert(type2aelembytes(store->as_Mem()->memory_type(), true) == 1 << shift->in(2)->get_int(), "scale should match"); + } + } else if (n->Opcode() == Op_ConvI2L && conv == NULL) { + if (n->in(1) == head->phi()) { + found_index = true; + conv = n; + } else { + msg = "unhandled input to ConvI2L"; + } + } else if (n == head->phi()) { + // no shift, check below for allowed cases + found_index = true; + } else { + msg = "unhandled node in address"; + msg_node = n; + } + } + + if (count == -1) { + msg = "malformed address expression"; + msg_node = store; + } + + if (!found_index) { + msg = "missing use of index"; + } + + // byte sized items won't have a shift + if (msg == NULL && shift == NULL && t != T_BYTE && t != T_BOOLEAN) { + msg = "can't find shift"; + msg_node = store; + } + + if (msg != NULL) { +#ifndef PRODUCT + if (TraceOptimizeFill) { + tty->print_cr("not fill intrinsic: %s", msg); + if (msg_node != NULL) msg_node->dump(); + } +#endif + return false; + } + + // No make sure all the other nodes in the loop can be handled + VectorSet ok(Thread::current()->resource_area()); + + // store related values are ok + ok.set(store->_idx); + ok.set(store->in(MemNode::Memory)->_idx); + + // Loop structure is ok + ok.set(head->_idx); + ok.set(head->loopexit()->_idx); + ok.set(head->phi()->_idx); + ok.set(head->incr()->_idx); + ok.set(head->loopexit()->cmp_node()->_idx); + ok.set(head->loopexit()->in(1)->_idx); + + // Address elements are ok + if (con) ok.set(con->_idx); + if (shift) ok.set(shift->_idx); + if (conv) ok.set(conv->_idx); + + for (uint i = 0; msg == NULL && i < lpt->_body.size(); i++) { + Node* n = lpt->_body.at(i); + if (n->outcnt() == 0) continue; // Ignore dead + if (ok.test(n->_idx)) continue; + // Backedge projection is ok + if (n->is_IfTrue() && n->in(0) == head->loopexit()) continue; + if (!n->is_AddP()) { + msg = "unhandled node"; + msg_node = n; + break; + } + } + + // Make sure no unexpected values are used outside the loop + for (uint i = 0; msg == NULL && i < lpt->_body.size(); i++) { + Node* n = lpt->_body.at(i); + // These values can be replaced with other nodes if they are used + // outside the loop. + if (n == store || n == head->loopexit() || n == head->incr()) continue; + for (SimpleDUIterator iter(n); iter.has_next(); iter.next()) { + Node* use = iter.get(); + if (!lpt->_body.contains(use)) { + msg = "node is used outside loop"; + // lpt->_body.dump(); + msg_node = n; + break; + } + } + } + +#ifdef ASSERT + if (TraceOptimizeFill) { + if (msg != NULL) { + tty->print_cr("no fill intrinsic: %s", msg); + if (msg_node != NULL) msg_node->dump(); + } else { + tty->print_cr("fill intrinsic for:"); + } + store->dump(); + if (Verbose) { + lpt->_body.dump(); + } + } +#endif + + return msg == NULL; +} + + + +bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) { + // Only for counted inner loops + if (!lpt->is_counted() || !lpt->is_inner()) { + return false; + } + + // Must have constant stride + CountedLoopNode* head = lpt->_head->as_CountedLoop(); + if (!head->stride_is_con() || !head->is_normal_loop()) { + return false; + } + + // Check that the body only contains a store of a loop invariant + // value that is indexed by the loop phi. + Node* store = NULL; + Node* store_value = NULL; + Node* shift = NULL; + Node* offset = NULL; + if (!match_fill_loop(lpt, store, store_value, shift, offset)) { + return false; + } + + // Now replace the whole loop body by a call to a fill routine that + // covers the same region as the loop. + Node* base = store->in(MemNode::Address)->as_AddP()->in(AddPNode::Base); + + // Build an expression for the beginning of the copy region + Node* index = head->init_trip(); +#ifdef _LP64 + index = new (C, 2) ConvI2LNode(index); + _igvn.register_new_node_with_optimizer(index); +#endif + if (shift != NULL) { + // byte arrays don't require a shift but others do. + index = new (C, 3) LShiftXNode(index, shift->in(2)); + _igvn.register_new_node_with_optimizer(index); + } + index = new (C, 4) AddPNode(base, base, index); + _igvn.register_new_node_with_optimizer(index); + Node* from = new (C, 4) AddPNode(base, index, offset); + _igvn.register_new_node_with_optimizer(from); + // Compute the number of elements to copy + Node* len = new (C, 3) SubINode(head->limit(), head->init_trip()); + _igvn.register_new_node_with_optimizer(len); + + BasicType t = store->as_Mem()->memory_type(); + bool aligned = false; + if (offset != NULL && head->init_trip()->is_Con()) { + int element_size = type2aelembytes(t); + aligned = (offset->find_intptr_t_type()->get_con() + head->init_trip()->get_int() * element_size) % HeapWordSize == 0; + } + + // Build a call to the fill routine + const char* fill_name; + address fill = StubRoutines::select_fill_function(t, aligned, fill_name); + assert(fill != NULL, "what?"); + + // Convert float/double to int/long for fill routines + if (t == T_FLOAT) { + store_value = new (C, 2) MoveF2INode(store_value); + _igvn.register_new_node_with_optimizer(store_value); + } else if (t == T_DOUBLE) { + store_value = new (C, 2) MoveD2LNode(store_value); + _igvn.register_new_node_with_optimizer(store_value); + } + + Node* mem_phi = store->in(MemNode::Memory); + Node* result_ctrl; + Node* result_mem; + const TypeFunc* call_type = OptoRuntime::array_fill_Type(); + int size = call_type->domain()->cnt(); + CallLeafNode *call = new (C, size) CallLeafNoFPNode(call_type, fill, + fill_name, TypeAryPtr::get_array_body_type(t)); + call->init_req(TypeFunc::Parms+0, from); + call->init_req(TypeFunc::Parms+1, store_value); + call->init_req(TypeFunc::Parms+2, len); + call->init_req( TypeFunc::Control, head->init_control()); + call->init_req( TypeFunc::I_O , C->top() ) ; // does no i/o + call->init_req( TypeFunc::Memory , mem_phi->in(LoopNode::EntryControl) ); + call->init_req( TypeFunc::ReturnAdr, C->start()->proj_out(TypeFunc::ReturnAdr) ); + call->init_req( TypeFunc::FramePtr, C->start()->proj_out(TypeFunc::FramePtr) ); + _igvn.register_new_node_with_optimizer(call); + result_ctrl = new (C, 1) ProjNode(call,TypeFunc::Control); + _igvn.register_new_node_with_optimizer(result_ctrl); + result_mem = new (C, 1) ProjNode(call,TypeFunc::Memory); + _igvn.register_new_node_with_optimizer(result_mem); + + // If this fill is tightly coupled to an allocation and overwrites + // the whole body, allow it to take over the zeroing. + AllocateNode* alloc = AllocateNode::Ideal_allocation(base, this); + if (alloc != NULL && alloc->is_AllocateArray()) { + Node* length = alloc->as_AllocateArray()->Ideal_length(); + if (head->limit() == length && + head->init_trip() == _igvn.intcon(0)) { + if (TraceOptimizeFill) { + tty->print_cr("Eliminated zeroing in allocation"); + } + alloc->maybe_set_complete(&_igvn); + } else { +#ifdef ASSERT + if (TraceOptimizeFill) { + tty->print_cr("filling array but bounds don't match"); + alloc->dump(); + head->init_trip()->dump(); + head->limit()->dump(); + length->dump(); + } +#endif + } + } + + // Redirect the old control and memory edges that are outside the loop. + Node* exit = head->loopexit()->proj_out(0); + _igvn.replace_node(exit, result_ctrl); + _igvn.replace_node(store, result_mem); + // Any uses the increment outside of the loop become the loop limit. + _igvn.replace_node(head->incr(), head->limit()); + + // Disconnect the head from the loop. + for (uint i = 0; i < lpt->_body.size(); i++) { + Node* n = lpt->_body.at(i); + _igvn.replace_node(n, C->top()); + } + + return true; +} diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index df9224af021..17277fa572a 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -1673,6 +1673,12 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) { _ltree_root->_child->loop_predication(this); } + if (OptimizeFill && UseLoopPredicate && C->has_loops() && !C->major_progress()) { + if (do_intrinsify_fill()) { + C->set_major_progress(); + } + } + // Perform iteration-splitting on inner loops. Split iterations to avoid // range checks or one-shot null checks. diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index 0fd4c6bbc50..3b3b42053a0 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -937,6 +937,12 @@ public: // same block. Split thru the Region. void do_split_if( Node *iff ); + // Conversion of fill/copy patterns into intrisic versions + bool do_intrinsify_fill(); + bool intrinsify_fill(IdealLoopTree* lpt); + bool match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& store_value, + Node*& shift, Node*& offset); + private: // Return a type based on condition control flow const TypeInt* filtered_type( Node *n, Node* n_ctrl); diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 78931baa42a..94178813e5b 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -456,6 +456,23 @@ void Matcher::init_first_stack_mask() { *idealreg2spillmask[Op_RegP] = *idealreg2regmask[Op_RegP]; idealreg2spillmask[Op_RegP]->OR(C->FIRST_STACK_mask()); + if (UseFPUForSpilling) { + // This mask logic assumes that the spill operations are + // symmetric and that the registers involved are the same size. + // On sparc for instance we may have to use 64 bit moves will + // kill 2 registers when used with F0-F31. + idealreg2spillmask[Op_RegI]->OR(*idealreg2regmask[Op_RegF]); + idealreg2spillmask[Op_RegF]->OR(*idealreg2regmask[Op_RegI]); +#ifdef _LP64 + idealreg2spillmask[Op_RegN]->OR(*idealreg2regmask[Op_RegF]); + idealreg2spillmask[Op_RegL]->OR(*idealreg2regmask[Op_RegD]); + idealreg2spillmask[Op_RegD]->OR(*idealreg2regmask[Op_RegL]); + idealreg2spillmask[Op_RegP]->OR(*idealreg2regmask[Op_RegD]); +#else + idealreg2spillmask[Op_RegP]->OR(*idealreg2regmask[Op_RegF]); +#endif + } + // Make up debug masks. Any spill slot plus callee-save registers. // Caller-save registers are assumed to be trashable by the various // inline-cache fixup routines. diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 9b6e26f9883..9297e4e224c 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1547,8 +1547,8 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const { adr->is_AddP() && off != Type::OffsetBot) { // For constant Strings treat the fields as compile time constants. Node* base = adr->in(AddPNode::Base); - if (base->Opcode() == Op_ConP) { - const TypeOopPtr* t = phase->type(base)->isa_oopptr(); + const TypeOopPtr* t = phase->type(base)->isa_oopptr(); + if (t != NULL && t->singleton()) { ciObject* string = t->const_oop(); ciConstant constant = string->as_instance()->field_value_by_offset(off); if (constant.basic_type() == T_INT) { diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index 010743959c7..959f4c8c846 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -1184,7 +1184,7 @@ void Compile::Fill_buffer() { MacroAssembler(cb).bind( blk_labels[b->_pre_order] ); else - assert( blk_labels[b->_pre_order].loc_pos() == cb->code_size(), + assert( blk_labels[b->_pre_order].loc_pos() == cb->insts_size(), "label position does not match code offset" ); uint last_inst = b->_nodes.size(); @@ -1225,7 +1225,7 @@ void Compile::Fill_buffer() { // If this requires all previous instructions be flushed, then do so if( is_sfn || is_mcall || mach->alignment_required() != 1) { cb->flush_bundle(true); - current_offset = cb->code_size(); + current_offset = cb->insts_size(); } // align the instruction if necessary @@ -1246,7 +1246,7 @@ void Compile::Fill_buffer() { _cfg->_bbs.map( nop->_idx, b ); nop->emit(*cb, _regalloc); cb->flush_bundle(true); - current_offset = cb->code_size(); + current_offset = cb->insts_size(); } // Remember the start of the last call in a basic block @@ -1348,12 +1348,12 @@ void Compile::Fill_buffer() { // Save the offset for the listing #ifndef PRODUCT if( node_offsets && n->_idx < node_offset_limit ) - node_offsets[n->_idx] = cb->code_size(); + node_offsets[n->_idx] = cb->insts_size(); #endif // "Normal" instruction case n->emit(*cb, _regalloc); - current_offset = cb->code_size(); + current_offset = cb->insts_size(); non_safepoints.observe_instruction(n, current_offset); // mcall is last "call" that can be a safepoint @@ -1372,13 +1372,12 @@ void Compile::Fill_buffer() { assert(delay_slot != NULL, "expecting delay slot node"); // Back up 1 instruction - cb->set_code_end( - cb->code_end()-Pipeline::instr_unit_size()); + cb->set_insts_end(cb->insts_end() - Pipeline::instr_unit_size()); // Save the offset for the listing #ifndef PRODUCT if( node_offsets && delay_slot->_idx < node_offset_limit ) - node_offsets[delay_slot->_idx] = cb->code_size(); + node_offsets[delay_slot->_idx] = cb->insts_size(); #endif // Support a SafePoint in the delay slot @@ -1420,7 +1419,7 @@ void Compile::Fill_buffer() { b->_nodes.insert( b->_nodes.size(), nop ); _cfg->_bbs.map( nop->_idx, b ); nop->emit(*cb, _regalloc); - current_offset = cb->code_size(); + current_offset = cb->insts_size(); } } @@ -1437,13 +1436,13 @@ void Compile::Fill_buffer() { // Compute the size of the first block _first_block_size = blk_labels[1].loc_pos() - blk_labels[0].loc_pos(); - assert(cb->code_size() < 500000, "method is unreasonably large"); + assert(cb->insts_size() < 500000, "method is unreasonably large"); // ------------------ #ifndef PRODUCT // Information on the size of the method, without the extraneous code - Scheduling::increment_method_size(cb->code_size()); + Scheduling::increment_method_size(cb->insts_size()); #endif // ------------------ diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp index cc4fbea16dd..871d1e96b3c 100644 --- a/hotspot/src/share/vm/opto/parse.hpp +++ b/hotspot/src/share/vm/opto/parse.hpp @@ -494,6 +494,7 @@ class Parse : public GraphKit { float dynamic_branch_prediction(float &cnt); float branch_prediction(float &cnt, BoolTest::mask btest, int target_bci); bool seems_never_taken(float prob); + bool seems_stable_comparison(BoolTest::mask btest, Node* c); void do_ifnull(BoolTest::mask btest, Node* c); void do_if(BoolTest::mask btest, Node* c); diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index 4711351d0b4..86a1f0928d4 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -892,6 +892,62 @@ bool Parse::seems_never_taken(float prob) { return prob < PROB_MIN; } +// True if the comparison seems to be the kind that will not change its +// statistics from true to false. See comments in adjust_map_after_if. +// This question is only asked along paths which are already +// classifed as untaken (by seems_never_taken), so really, +// if a path is never taken, its controlling comparison is +// already acting in a stable fashion. If the comparison +// seems stable, we will put an expensive uncommon trap +// on the untaken path. To be conservative, and to allow +// partially executed counted loops to be compiled fully, +// we will plant uncommon traps only after pointer comparisons. +bool Parse::seems_stable_comparison(BoolTest::mask btest, Node* cmp) { + for (int depth = 4; depth > 0; depth--) { + // The following switch can find CmpP here over half the time for + // dynamic language code rich with type tests. + // Code using counted loops or array manipulations (typical + // of benchmarks) will have many (>80%) CmpI instructions. + switch (cmp->Opcode()) { + case Op_CmpP: + // A never-taken null check looks like CmpP/BoolTest::eq. + // These certainly should be closed off as uncommon traps. + if (btest == BoolTest::eq) + return true; + // A never-failed type check looks like CmpP/BoolTest::ne. + // Let's put traps on those, too, so that we don't have to compile + // unused paths with indeterminate dynamic type information. + if (ProfileDynamicTypes) + return true; + return false; + + case Op_CmpI: + // A small minority (< 10%) of CmpP are masked as CmpI, + // as if by boolean conversion ((p == q? 1: 0) != 0). + // Detect that here, even if it hasn't optimized away yet. + // Specifically, this covers the 'instanceof' operator. + if (btest == BoolTest::ne || btest == BoolTest::eq) { + if (_gvn.type(cmp->in(2))->singleton() && + cmp->in(1)->is_Phi()) { + PhiNode* phi = cmp->in(1)->as_Phi(); + int true_path = phi->is_diamond_phi(); + if (true_path > 0 && + _gvn.type(phi->in(1))->singleton() && + _gvn.type(phi->in(2))->singleton()) { + // phi->region->if_proj->ifnode->bool->cmp + BoolNode* bol = phi->in(0)->in(1)->in(0)->in(1)->as_Bool(); + btest = bol->_test._test; + cmp = bol->in(1); + continue; + } + } + } + return false; + } + } + return false; +} + //-------------------------------repush_if_args-------------------------------- // Push arguments of an "if" bytecode back onto the stack by adjusting _sp. inline int Parse::repush_if_args() { @@ -1137,19 +1193,22 @@ void Parse::adjust_map_after_if(BoolTest::mask btest, Node* c, float prob, bool is_fallthrough = (path == successor_for_bci(iter().next_bci())); - int cop = c->Opcode(); - if (seems_never_taken(prob) && cop == Op_CmpP && btest == BoolTest::eq) { - // (An earlier version of do_if omitted '&& btest == BoolTest::eq'.) - // + if (seems_never_taken(prob) && seems_stable_comparison(btest, c)) { // If this might possibly turn into an implicit null check, // and the null has never yet been seen, we need to generate // an uncommon trap, so as to recompile instead of suffering // with very slow branches. (We'll get the slow branches if // the program ever changes phase and starts seeing nulls here.) // - // The tests we worry about are of the form (p == null). - // We do not simply inspect for a null constant, since a node may + // We do not inspect for a null constant, since a node may // optimize to 'null' later on. + // + // Null checks, and other tests which expect inequality, + // show btest == BoolTest::eq along the non-taken branch. + // On the other hand, type tests, must-be-null tests, + // and other tests which expect pointer equality, + // show btest == BoolTest::ne along the non-taken branch. + // We prune both types of branches if they look unused. repush_if_args(); // We need to mark this branch as taken so that if we recompile we will // see that it is possible. In the tiered system the interpreter doesn't diff --git a/hotspot/src/share/vm/opto/parseHelper.cpp b/hotspot/src/share/vm/opto/parseHelper.cpp index cd645c2960e..3e50e542951 100644 --- a/hotspot/src/share/vm/opto/parseHelper.cpp +++ b/hotspot/src/share/vm/opto/parseHelper.cpp @@ -119,7 +119,11 @@ void Parse::do_instanceof() { } // Push the bool result back on stack - push( gen_instanceof( pop(), makecon(TypeKlassPtr::make(klass)) ) ); + Node* res = gen_instanceof(peek(), makecon(TypeKlassPtr::make(klass))); + + // Pop from stack AFTER gen_instanceof because it can uncommon trap. + pop(); + push(res); } //------------------------------array_store_check------------------------------ diff --git a/hotspot/src/share/vm/opto/reg_split.cpp b/hotspot/src/share/vm/opto/reg_split.cpp index a4fee6f7cc2..9e3967e3656 100644 --- a/hotspot/src/share/vm/opto/reg_split.cpp +++ b/hotspot/src/share/vm/opto/reg_split.cpp @@ -975,6 +975,19 @@ uint PhaseChaitin::Split( uint maxlrg ) { insidx++; // Reset iterator to skip USE side split continue; } + + if (UseFPUForSpilling && n->is_Call() && !uup && !dup ) { + // The use at the call can force the def down so insert + // a split before the use to allow the def more freedom. + maxlrg = split_USE(def,b,n,inpidx,maxlrg,dup,false, splits,slidx); + // If it wasn't split bail + if (!maxlrg) { + return 0; + } + insidx++; // Reset iterator to skip USE side split + continue; + } + // Here is the logic chart which describes USE Splitting: // 0 = false or DOWN, 1 = true or UP // diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index e56b139d6bb..389c3f9ee7f 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -645,6 +645,22 @@ const TypeFunc* OptoRuntime::generic_arraycopy_Type() { } +const TypeFunc* OptoRuntime::array_fill_Type() { + // create input type (domain) + const Type** fields = TypeTuple::fields(3); + fields[TypeFunc::Parms+0] = TypePtr::NOTNULL; + fields[TypeFunc::Parms+1] = TypeInt::INT; + fields[TypeFunc::Parms+2] = TypeInt::INT; + const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms + 3, fields); + + // create result type + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms+0] = NULL; // void + const TypeTuple *range = TypeTuple::make(TypeFunc::Parms, fields); + + return TypeFunc::make(domain, range); +} + //------------- Interpreter state access for on stack replacement const TypeFunc* OptoRuntime::osr_end_Type() { // create input type (domain) diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp index 9c930426bf9..c5053853060 100644 --- a/hotspot/src/share/vm/opto/runtime.hpp +++ b/hotspot/src/share/vm/opto/runtime.hpp @@ -260,6 +260,8 @@ private: static const TypeFunc* generic_arraycopy_Type(); static const TypeFunc* slow_arraycopy_Type(); // the full routine + static const TypeFunc* array_fill_Type(); + // leaf on stack replacement interpreter accessor types static const TypeFunc* osr_end_Type(); diff --git a/hotspot/src/share/vm/opto/stringopts.cpp b/hotspot/src/share/vm/opto/stringopts.cpp index 0f80acec8a9..2584652a027 100644 --- a/hotspot/src/share/vm/opto/stringopts.cpp +++ b/hotspot/src/share/vm/opto/stringopts.cpp @@ -157,7 +157,7 @@ class StringConcat : public ResourceObj { Node* uct = _uncommon_traps.at(u); // Build a new call using the jvms state of the allocate - address call_addr = SharedRuntime::uncommon_trap_blob()->instructions_begin(); + address call_addr = SharedRuntime::uncommon_trap_blob()->entry_point(); const TypeFunc* call_type = OptoRuntime::uncommon_trap_Type(); int size = call_type->domain()->cnt(); const TypePtr* no_memory_effects = NULL; diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index 7f95984273f..284159974ae 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -314,7 +314,7 @@ void Type::Initialize_shared(Compile* current) { mreg2type[Op_RegL] = TypeLong::LONG; mreg2type[Op_RegFlags] = TypeInt::CC; - TypeAryPtr::RANGE = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), current->env()->Object_klass(), false, arrayOopDesc::length_offset_in_bytes()); + TypeAryPtr::RANGE = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), NULL /* current->env()->Object_klass() */, false, arrayOopDesc::length_offset_in_bytes()); TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot); @@ -3369,7 +3369,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const { tary = TypeAry::make(Type::BOTTOM, tary->_size); } } - bool xk; + bool xk = false; switch (tap->ptr()) { case AnyNull: case TopPTR: @@ -3391,9 +3391,10 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const { o = tap->const_oop(); xk = true; } else { - xk = this->_klass_is_exact; + // Only precise for identical arrays + xk = this->_klass_is_exact && (klass() == tap->klass()); } - return TypeAryPtr::make( ptr, o, tary, tap->_klass, xk, off, instance_id ); + return TypeAryPtr::make( ptr, o, tary, lazy_klass, xk, off, instance_id ); } case NotNull: case BotPTR: @@ -3683,12 +3684,10 @@ int TypeKlassPtr::hash(void) const { } -//------------------------------klass------------------------------------------ -// Return the defining klass for this class -ciKlass* TypeAryPtr::klass() const { - if( _klass ) return _klass; // Return cached value, if possible - - // Oops, need to compute _klass and cache it +//----------------------compute_klass------------------------------------------ +// Compute the defining klass for this class +ciKlass* TypeAryPtr::compute_klass(DEBUG_ONLY(bool verify)) const { + // Compute _klass based on element type. ciKlass* k_ary = NULL; const TypeInstPtr *tinst; const TypeAryPtr *tary; @@ -3715,11 +3714,39 @@ ciKlass* TypeAryPtr::klass() const { } else { // Cannot compute array klass directly from basic type, // since subtypes of TypeInt all have basic type T_INT. +#ifdef ASSERT + if (verify && el->isa_int()) { + // Check simple cases when verifying klass. + BasicType bt = T_ILLEGAL; + if (el == TypeInt::BYTE) { + bt = T_BYTE; + } else if (el == TypeInt::SHORT) { + bt = T_SHORT; + } else if (el == TypeInt::CHAR) { + bt = T_CHAR; + } else if (el == TypeInt::INT) { + bt = T_INT; + } else { + return _klass; // just return specified klass + } + return ciTypeArrayKlass::make(bt); + } +#endif assert(!el->isa_int(), "integral arrays must be pre-equipped with a class"); // Compute array klass directly from basic type k_ary = ciTypeArrayKlass::make(el->basic_type()); } + return k_ary; +} + +//------------------------------klass------------------------------------------ +// Return the defining klass for this class +ciKlass* TypeAryPtr::klass() const { + if( _klass ) return _klass; // Return cached value, if possible + + // Oops, need to compute _klass and cache it + ciKlass* k_ary = compute_klass(); if( this != TypeAryPtr::OOPS ) { // The _klass field acts as a cache of the underlying diff --git a/hotspot/src/share/vm/opto/type.hpp b/hotspot/src/share/vm/opto/type.hpp index a922307dc7f..779280237e3 100644 --- a/hotspot/src/share/vm/opto/type.hpp +++ b/hotspot/src/share/vm/opto/type.hpp @@ -831,11 +831,30 @@ class TypeInstPtr : public TypeOopPtr { //------------------------------TypeAryPtr------------------------------------- // Class of Java array pointers class TypeAryPtr : public TypeOopPtr { - TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id ) : TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id), _ary(ary) {}; + TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id ) : TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id), _ary(ary) { +#ifdef ASSERT + if (k != NULL) { + // Verify that specified klass and TypeAryPtr::klass() follow the same rules. + ciKlass* ck = compute_klass(true); + if (k != ck) { + this->dump(); tty->cr(); + tty->print(" k: "); + k->print(); tty->cr(); + tty->print("ck: "); + if (ck != NULL) ck->print(); + else tty->print(""); + tty->cr(); + assert(false, "unexpected TypeAryPtr::_klass"); + } + } +#endif + } virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing const TypeAry *_ary; // Array we point into + ciKlass* compute_klass(DEBUG_ONLY(bool verify = false)) const; + public: // Accessors ciKlass* klass() const; diff --git a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp index 0547de26783..f742a99e9a4 100644 --- a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp +++ b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp @@ -114,7 +114,7 @@ void CodeBlobCollector::do_blob(CodeBlob* cb) { // check if this starting address has been seen already - the // assumption is that stubs are inserted into the list before the // enclosing BufferBlobs. - address addr = cb->instructions_begin(); + address addr = cb->code_begin(); for (int i=0; i<_global_code_blobs->length(); i++) { JvmtiCodeBlobDesc* scb = _global_code_blobs->at(i); if (addr == scb->code_begin()) { @@ -123,8 +123,7 @@ void CodeBlobCollector::do_blob(CodeBlob* cb) { } // record the CodeBlob details as a JvmtiCodeBlobDesc - JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(cb->name(), cb->instructions_begin(), - cb->instructions_end()); + JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(cb->name(), cb->code_begin(), cb->code_end()); _global_code_blobs->append(scb); } diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp index a4c2828dacb..d07f5902b4f 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp @@ -687,8 +687,8 @@ class JvmtiCompiledMethodLoadEventMark : public JvmtiMethodEventMark { public: JvmtiCompiledMethodLoadEventMark(JavaThread *thread, nmethod *nm, void* compile_info_ptr = NULL) : JvmtiMethodEventMark(thread,methodHandle(thread, nm->method())) { - _code_data = nm->code_begin(); - _code_size = nm->code_size(); + _code_data = nm->insts_begin(); + _code_size = nm->insts_size(); _compile_info = compile_info_ptr; // Set void pointer of compiledMethodLoad Event. Default value is NULL. JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nm, &_map, &_map_length); } diff --git a/hotspot/src/share/vm/prims/methodHandleWalk.cpp b/hotspot/src/share/vm/prims/methodHandleWalk.cpp index 6a82f4b2436..ca6a2315013 100644 --- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp +++ b/hotspot/src/share/vm/prims/methodHandleWalk.cpp @@ -333,8 +333,7 @@ MethodHandleWalker::walk(TRAPS) { ArgToken arglist[2]; arglist[0] = arg; // outgoing value arglist[1] = ArgToken(); // sentinel - assert(false, "I think the argument count must be 1 instead of 0"); - arg = make_invoke(NULL, boxer, Bytecodes::_invokevirtual, false, 0, &arglist[0], CHECK_(empty)); + arg = make_invoke(NULL, boxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_(empty)); change_argument(src, arg_slot, T_OBJECT, arg); break; } @@ -979,7 +978,7 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid, // Inline the method. InvocationCounter* ic = m->invocation_counter(); - ic->set_carry(); + ic->set_carry_flag(); for (int i = 0; i < argc; i++) { ArgToken arg = argv[i]; @@ -1209,7 +1208,7 @@ methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const { // Set the carry bit of the invocation counter to force inlining of // the adapter. InvocationCounter* ic = m->invocation_counter(); - ic->set_carry(); + ic->set_carry_flag(); // Rewrite the method and set up the constant pool cache. objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(nullHandle)); @@ -1398,7 +1397,9 @@ public: extern "C" void print_method_handle(oop mh) { - if (java_dyn_MethodHandle::is_instance(mh)) { + if (!mh->is_oop()) { + tty->print_cr("*** not a method handle: "INTPTR_FORMAT, (intptr_t)mh); + } else if (java_dyn_MethodHandle::is_instance(mh)) { //MethodHandlePrinter::print(mh); } else { tty->print("*** not a method handle: "); diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 7b3acfda1e1..650b3d30917 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -113,8 +113,7 @@ void MethodHandles::generate_adapters() { _adapter_code = MethodHandlesAdapterBlob::create(_adapter_code_size); if (_adapter_code == NULL) vm_exit_out_of_memory(_adapter_code_size, "CodeCache: no room for MethodHandles adapters"); - CodeBuffer code(_adapter_code->instructions_begin(), _adapter_code->instructions_size()); - + CodeBuffer code(_adapter_code); MethodHandlesAdapterGenerator g(&code); g.generate(); } diff --git a/hotspot/src/share/vm/prims/methodHandles.hpp b/hotspot/src/share/vm/prims/methodHandles.hpp index 4c048acabed..e6a6f2b00bb 100644 --- a/hotspot/src/share/vm/prims/methodHandles.hpp +++ b/hotspot/src/share/vm/prims/methodHandles.hpp @@ -446,6 +446,8 @@ class MethodHandles: AllStatic { RegisterOrConstant arg_slots, Register argslot_reg, Register temp_reg, Register temp2_reg, Register temp3_reg = noreg); + + static void trace_method_handle(MacroAssembler* _masm, const char* adaptername) PRODUCT_RETURN; }; diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 48b61217130..78bccb66cf9 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -50,7 +50,6 @@ bool Arguments::_AlwaysCompileLoopMethods = AlwaysCompileLoopMethods; bool Arguments::_UseOnStackReplacement = UseOnStackReplacement; bool Arguments::_BackgroundCompilation = BackgroundCompilation; bool Arguments::_ClipInlining = ClipInlining; -intx Arguments::_Tier2CompileThreshold = Tier2CompileThreshold; char* Arguments::SharedArchivePath = NULL; @@ -121,7 +120,7 @@ void Arguments::init_system_properties() { PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.name", "Java Virtual Machine Specification", false)); PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.vendor", - "Sun Microsystems Inc.", false)); + JDK_Version::is_gte_jdk17x_version() ? "Oracle Corporation" : "Sun Microsystems Inc.", false)); PropertyList_add(&_system_properties, new SystemProperty("java.vm.version", VM_Version::vm_release(), false)); PropertyList_add(&_system_properties, new SystemProperty("java.vm.name", VM_Version::vm_name(), false)); PropertyList_add(&_system_properties, new SystemProperty("java.vm.vendor", VM_Version::vm_vendor(), false)); @@ -184,6 +183,8 @@ static ObsoleteFlag obsolete_jvm_flags[] = { { "DefaultMaxRAM", JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) }, { "DefaultInitialRAMFraction", JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) }, + { "UseDepthFirstScavengeOrder", + JDK_Version::jdk_update(6,22), JDK_Version::jdk(7) }, { NULL, JDK_Version(0), JDK_Version(0) } }; @@ -911,7 +912,6 @@ void Arguments::set_mode_flags(Mode mode) { AlwaysCompileLoopMethods = Arguments::_AlwaysCompileLoopMethods; UseOnStackReplacement = Arguments::_UseOnStackReplacement; BackgroundCompilation = Arguments::_BackgroundCompilation; - Tier2CompileThreshold = Arguments::_Tier2CompileThreshold; // Change from defaults based on mode switch (mode) { @@ -948,6 +948,31 @@ static void no_shared_spaces() { } } +void Arguments::set_tiered_flags() { + if (FLAG_IS_DEFAULT(CompilationPolicyChoice)) { + FLAG_SET_DEFAULT(CompilationPolicyChoice, 2); + } + + if (CompilationPolicyChoice < 2) { + vm_exit_during_initialization( + "Incompatible compilation policy selected", NULL); + } + +#ifdef _LP64 + if (FLAG_IS_DEFAULT(UseCompressedOops) || FLAG_IS_ERGO(UseCompressedOops)) { + UseCompressedOops = false; + } + if (UseCompressedOops) { + vm_exit_during_initialization( + "Tiered compilation is not supported with compressed oops yet", NULL); + } +#endif + // Increase the code cache size - tiered compiles a lot more. + if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) { + FLAG_SET_DEFAULT(ReservedCodeCacheSize, ReservedCodeCacheSize * 2); + } +} + #ifndef KERNEL // If the user has chosen ParallelGCThreads > 0, we set UseParNewGC // if it's not explictly set or unset. If the user has chosen @@ -1248,7 +1273,8 @@ bool verify_object_alignment() { } inline uintx max_heap_for_compressed_oops() { - LP64_ONLY(return OopEncodingHeapMax - MaxPermSize - os::vm_page_size()); + // Heap should be above HeapBaseMinAddress to get zero based compressed oops. + LP64_ONLY(return OopEncodingHeapMax - MaxPermSize - os::vm_page_size() - HeapBaseMinAddress); NOT_LP64(ShouldNotReachHere(); return 0); } @@ -1297,7 +1323,7 @@ void Arguments::set_ergonomics_flags() { // Check that UseCompressedOops can be set with the max heap size allocated // by ergonomics. if (MaxHeapSize <= max_heap_for_compressed_oops()) { -#ifndef COMPILER1 +#if !defined(COMPILER1) || defined(TIERED) if (FLAG_IS_DEFAULT(UseCompressedOops) && !UseG1GC) { FLAG_SET_ERGO(bool, UseCompressedOops, true); } @@ -1511,6 +1537,9 @@ void Arguments::set_aggressive_opts_flags() { if (AggressiveOpts && FLAG_IS_DEFAULT(OptimizeStringConcat)) { FLAG_SET_DEFAULT(OptimizeStringConcat, true); } + if (AggressiveOpts && FLAG_IS_DEFAULT(OptimizeFill)) { + FLAG_SET_DEFAULT(OptimizeFill, true); + } #endif if (AggressiveOpts) { @@ -1559,6 +1588,18 @@ bool Arguments::verify_interval(uintx val, uintx min, return false; } +bool Arguments::verify_min_value(intx val, intx min, const char* name) { + // Returns true if given value is greater than specified min threshold + // false, otherwise. + if (val >= min ) { + return true; + } + jio_fprintf(defaultStream::error_stream(), + "%s of " INTX_FORMAT " is invalid; must be greater than " INTX_FORMAT "\n", + name, val, min); + return false; +} + bool Arguments::verify_percentage(uintx value, const char* name) { if (value <= 100) { return true; @@ -1611,6 +1652,16 @@ bool Arguments::check_gc_consistency() { return status; } +// Check stack pages settings +bool Arguments::check_stack_pages() +{ + bool status = true; + status = status && verify_min_value(StackYellowPages, 1, "StackYellowPages"); + status = status && verify_min_value(StackRedPages, 1, "StackRedPages"); + status = status && verify_min_value(StackShadowPages, 1, "StackShadowPages"); + return status; +} + // Check the consistency of vm_init_args bool Arguments::check_vm_args_consistency() { // Method for adding checks for flag consistency. @@ -1723,6 +1774,7 @@ bool Arguments::check_vm_args_consistency() { } status = status && check_gc_consistency(); + status = status && check_stack_pages(); if (_has_alloc_profile) { if (UseParallelGC || UseParallelOldGC) { @@ -1905,7 +1957,6 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs* args) { Arguments::_UseOnStackReplacement = UseOnStackReplacement; Arguments::_ClipInlining = ClipInlining; Arguments::_BackgroundCompilation = BackgroundCompilation; - Arguments::_Tier2CompileThreshold = Tier2CompileThreshold; // Parse JAVA_TOOL_OPTIONS environment variable (if present) jint result = parse_java_tool_options_environment_variable(&scp, &scp_assembly_required); @@ -2623,23 +2674,6 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req set_mode_flags(_int); } -#ifdef TIERED - // If we are using tiered compilation in the tiered vm then c1 will - // do the profiling and we don't want to waste that time in the - // interpreter. - if (TieredCompilation) { - ProfileInterpreter = false; - } else { - // Since we are running vanilla server we must adjust the compile threshold - // unless the user has already adjusted it because the default threshold assumes - // we will run tiered. - - if (FLAG_IS_DEFAULT(CompileThreshold)) { - CompileThreshold = Tier2CompileThreshold; - } - } -#endif // TIERED - #ifndef COMPILER2 // Don't degrade server performance for footprint if (FLAG_IS_DEFAULT(UseLargePages) && @@ -2654,7 +2688,6 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req // Tiered compilation is undefined with C1. TieredCompilation = false; - #else if (!FLAG_IS_DEFAULT(OptoLoopAlignment) && FLAG_IS_DEFAULT(MaxLoopPad)) { FLAG_SET_DEFAULT(MaxLoopPad, OptoLoopAlignment-1); @@ -2830,6 +2863,13 @@ jint Arguments::parse(const JavaVMInitArgs* args) { CommandLineFlags::printFlags(); vm_exit(0); } + +#ifndef PRODUCT + if (match_option(option, "-XX:+PrintFlagsWithComments", &tail)) { + CommandLineFlags::printFlags(true); + vm_exit(0); + } +#endif } if (IgnoreUnrecognizedVMOptions) { @@ -2911,7 +2951,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { PrintGC = true; } -#if defined(_LP64) && defined(COMPILER1) +#if defined(_LP64) && defined(COMPILER1) && !defined(TIERED) UseCompressedOops = false; #endif @@ -2942,6 +2982,16 @@ jint Arguments::parse(const JavaVMInitArgs* args) { return JNI_EINVAL; } + if (TieredCompilation) { + set_tiered_flags(); + } else { + // Check if the policy is valid. Policies 0 and 1 are valid for non-tiered setup. + if (CompilationPolicyChoice >= 2) { + vm_exit_during_initialization( + "Incompatible compilation policy selected", NULL); + } + } + #ifndef KERNEL if (UseConcMarkSweepGC) { // Set flags for CMS and ParNew. Check UseConcMarkSweep first @@ -3003,10 +3053,6 @@ jint Arguments::parse(const JavaVMInitArgs* args) { CommandLineFlags::printSetFlags(); } - if (PrintFlagsFinal) { - CommandLineFlags::printFlags(); - } - // Apply CPU specific policy for the BiasedLocking if (UseBiasedLocking) { if (!VM_Version::use_biased_locking() && diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index 15cf8ee3d4c..949d4560f97 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -288,8 +288,9 @@ class Arguments : AllStatic { static bool _BackgroundCompilation; static bool _ClipInlining; static bool _CIDynamicCompilePriority; - static intx _Tier2CompileThreshold; + // Tiered + static void set_tiered_flags(); // CMS/ParNew garbage collectors static void set_parnew_gc_flags(); static void set_cms_and_parnew_gc_flags(); @@ -338,6 +339,7 @@ class Arguments : AllStatic { } static bool verify_interval(uintx val, uintx min, uintx max, const char* name); + static bool verify_min_value(intx val, intx min, const char* name); static bool verify_percentage(uintx value, const char* name); static void describe_range_error(ArgsRange errcode); static ArgsRange check_memory_size(julong size, julong min_size); @@ -400,6 +402,8 @@ class Arguments : AllStatic { static bool check_gc_consistency(); // Check consistecy or otherwise of VM argument settings static bool check_vm_args_consistency(); + // Check stack pages settings + static bool check_stack_pages(); // Used by os_solaris static bool process_settings_file(const char* file_name, bool should_exist, jboolean ignore_unrecognized); diff --git a/hotspot/src/share/vm/runtime/compilationPolicy.cpp b/hotspot/src/share/vm/runtime/compilationPolicy.cpp index 96b02db43d1..3d1ccc0a381 100644 --- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp +++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp @@ -45,10 +45,17 @@ void compilationPolicy_init() { Unimplemented(); #endif break; - + case 2: +#ifdef TIERED + CompilationPolicy::set_policy(new SimpleThresholdPolicy()); +#else + Unimplemented(); +#endif + break; default: - fatal("CompilationPolicyChoice must be in the range: [0-1]"); + fatal("CompilationPolicyChoice must be in the range: [0-2]"); } + CompilationPolicy::policy()->initialize(); } void CompilationPolicy::completed_vm_startup() { @@ -61,16 +68,16 @@ void CompilationPolicy::completed_vm_startup() { // Returns true if m must be compiled before executing it // This is intended to force compiles for methods (usually for // debugging) that would otherwise be interpreted for some reason. -bool CompilationPolicy::mustBeCompiled(methodHandle m) { +bool CompilationPolicy::must_be_compiled(methodHandle m, int comp_level) { if (m->has_compiled_code()) return false; // already compiled - if (!canBeCompiled(m)) return false; + if (!can_be_compiled(m, comp_level)) return false; return !UseInterpreter || // must compile all methods (UseCompiler && AlwaysCompileLoopMethods && m->has_loops() && CompileBroker::should_compile_new_jobs()); // eagerly compile loop methods } // Returns true if m is allowed to be compiled -bool CompilationPolicy::canBeCompiled(methodHandle m) { +bool CompilationPolicy::can_be_compiled(methodHandle m, int comp_level) { if (m->is_abstract()) return false; if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false; @@ -83,8 +90,16 @@ bool CompilationPolicy::canBeCompiled(methodHandle m) { if (!AbstractInterpreter::can_be_compiled(m)) { return false; } + if (comp_level == CompLevel_all) { + return !m->is_not_compilable(CompLevel_simple) && !m->is_not_compilable(CompLevel_full_optimization); + } else { + return !m->is_not_compilable(comp_level); + } +} - return !m->is_not_compilable(); +bool CompilationPolicy::is_compilation_enabled() { + // NOTE: CompileBroker::should_compile_new_jobs() checks for UseCompiler + return !delay_compilation_during_startup() && CompileBroker::should_compile_new_jobs(); } #ifndef PRODUCT @@ -94,7 +109,7 @@ void CompilationPolicy::print_time() { tty->print_cr (" Total: %3.3f sec.", _accumulated_time.seconds()); } -static void trace_osr_completion(nmethod* osr_nm) { +void NonTieredCompPolicy::trace_osr_completion(nmethod* osr_nm) { if (TraceOnStackReplacement) { if (osr_nm == NULL) tty->print_cr("compilation failed"); else tty->print_cr("nmethod " INTPTR_FORMAT, osr_nm); @@ -102,7 +117,35 @@ static void trace_osr_completion(nmethod* osr_nm) { } #endif // !PRODUCT -void CompilationPolicy::reset_counter_for_invocation_event(methodHandle m) { +void NonTieredCompPolicy::initialize() { + // Setup the compiler thread numbers + if (CICompilerCountPerCPU) { + // Example: if CICompilerCountPerCPU is true, then we get + // max(log2(8)-1,1) = 2 compiler threads on an 8-way machine. + // May help big-app startup time. + _compiler_count = MAX2(log2_intptr(os::active_processor_count())-1,1); + } else { + _compiler_count = CICompilerCount; + } +} + +int NonTieredCompPolicy::compiler_count(CompLevel comp_level) { +#ifdef COMPILER1 + if (is_c1_compile(comp_level)) { + return _compiler_count; + } +#endif + +#ifdef COMPILER2 + if (is_c2_compile(comp_level)) { + return _compiler_count; + } +#endif + + return 0; +} + +void NonTieredCompPolicy::reset_counter_for_invocation_event(methodHandle m) { // Make sure invocation and backedge counter doesn't overflow again right away // as would be the case for native methods. @@ -114,7 +157,7 @@ void CompilationPolicy::reset_counter_for_invocation_event(methodHandle m) { assert(!m->was_never_executed(), "don't reset to 0 -- could be mistaken for never-executed"); } -void CompilationPolicy::reset_counter_for_back_branch_event(methodHandle m) { +void NonTieredCompPolicy::reset_counter_for_back_branch_event(methodHandle m) { // Delay next back-branch event but pump up invocation counter to triger // whole method compilation. InvocationCounter* i = m->invocation_counter(); @@ -128,6 +171,185 @@ void CompilationPolicy::reset_counter_for_back_branch_event(methodHandle m) { b->set(b->state(), CompileThreshold / 2); } +// +// CounterDecay +// +// Interates through invocation counters and decrements them. This +// is done at each safepoint. +// +class CounterDecay : public AllStatic { + static jlong _last_timestamp; + static void do_method(methodOop m) { + m->invocation_counter()->decay(); + } +public: + static void decay(); + static bool is_decay_needed() { + return (os::javaTimeMillis() - _last_timestamp) > CounterDecayMinIntervalLength; + } +}; + +jlong CounterDecay::_last_timestamp = 0; + +void CounterDecay::decay() { + _last_timestamp = os::javaTimeMillis(); + + // This operation is going to be performed only at the end of a safepoint + // and hence GC's will not be going on, all Java mutators are suspended + // at this point and hence SystemDictionary_lock is also not needed. + assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint"); + int nclasses = SystemDictionary::number_of_classes(); + double classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 / + CounterHalfLifeTime); + for (int i = 0; i < classes_per_tick; i++) { + klassOop k = SystemDictionary::try_get_next_class(); + if (k != NULL && k->klass_part()->oop_is_instance()) { + instanceKlass::cast(k)->methods_do(do_method); + } + } +} + +// Called at the end of the safepoint +void NonTieredCompPolicy::do_safepoint_work() { + if(UseCounterDecay && CounterDecay::is_decay_needed()) { + CounterDecay::decay(); + } +} + +void NonTieredCompPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) { + ScopeDesc* sd = trap_scope; + for (; !sd->is_top(); sd = sd->sender()) { + // Reset ICs of inlined methods, since they can trigger compilations also. + sd->method()->invocation_counter()->reset(); + } + InvocationCounter* c = sd->method()->invocation_counter(); + if (is_osr) { + // It was an OSR method, so bump the count higher. + c->set(c->state(), CompileThreshold); + } else { + c->reset(); + } + sd->method()->backedge_counter()->reset(); +} + +// This method can be called by any component of the runtime to notify the policy +// that it's recommended to delay the complation of this method. +void NonTieredCompPolicy::delay_compilation(methodOop method) { + method->invocation_counter()->decay(); + method->backedge_counter()->decay(); +} + +void NonTieredCompPolicy::disable_compilation(methodOop method) { + method->invocation_counter()->set_state(InvocationCounter::wait_for_nothing); + method->backedge_counter()->set_state(InvocationCounter::wait_for_nothing); +} + +CompileTask* NonTieredCompPolicy::select_task(CompileQueue* compile_queue) { + return compile_queue->first(); +} + +bool NonTieredCompPolicy::is_mature(methodOop method) { + methodDataOop mdo = method->method_data(); + assert(mdo != NULL, "Should be"); + uint current = mdo->mileage_of(method); + uint initial = mdo->creation_mileage(); + if (current < initial) + return true; // some sort of overflow + uint target; + if (ProfileMaturityPercentage <= 0) + target = (uint) -ProfileMaturityPercentage; // absolute value + else + target = (uint)( (ProfileMaturityPercentage * CompileThreshold) / 100 ); + return (current >= initial + target); +} + +nmethod* NonTieredCompPolicy::event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, TRAPS) { + assert(comp_level == CompLevel_none, "This should be only called from the interpreter"); + NOT_PRODUCT(trace_frequency_counter_overflow(method, branch_bci, bci)); + if (JvmtiExport::can_post_interpreter_events()) { + assert(THREAD->is_Java_thread(), "Wrong type of thread"); + if (((JavaThread*)THREAD)->is_interp_only_mode()) { + // If certain JVMTI events (e.g. frame pop event) are requested then the + // thread is forced to remain in interpreted code. This is + // implemented partly by a check in the run_compiled_code + // section of the interpreter whether we should skip running + // compiled code, and partly by skipping OSR compiles for + // interpreted-only threads. + if (bci != InvocationEntryBci) { + reset_counter_for_back_branch_event(method); + return NULL; + } + } + } + if (bci == InvocationEntryBci) { + // when code cache is full, compilation gets switched off, UseCompiler + // is set to false + if (!method->has_compiled_code() && UseCompiler) { + method_invocation_event(method, CHECK_NULL); + } else { + // Force counter overflow on method entry, even if no compilation + // happened. (The method_invocation_event call does this also.) + reset_counter_for_invocation_event(method); + } + // compilation at an invocation overflow no longer goes and retries test for + // compiled method. We always run the loser of the race as interpreted. + // so return NULL + return NULL; + } else { + // counter overflow in a loop => try to do on-stack-replacement + nmethod* osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true); + NOT_PRODUCT(trace_osr_request(method, osr_nm, bci)); + // when code cache is full, we should not compile any more... + if (osr_nm == NULL && UseCompiler) { + method_back_branch_event(method, bci, CHECK_NULL); + osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true); + } + if (osr_nm == NULL) { + reset_counter_for_back_branch_event(method); + return NULL; + } + return osr_nm; + } + return NULL; +} + +#ifndef PRODUCT +void NonTieredCompPolicy::trace_frequency_counter_overflow(methodHandle m, int branch_bci, int bci) { + if (TraceInvocationCounterOverflow) { + InvocationCounter* ic = m->invocation_counter(); + InvocationCounter* bc = m->backedge_counter(); + ResourceMark rm; + const char* msg = + bci == InvocationEntryBci + ? "comp-policy cntr ovfl @ %d in entry of " + : "comp-policy cntr ovfl @ %d in loop of "; + tty->print(msg, bci); + m->print_value(); + tty->cr(); + ic->print(); + bc->print(); + if (ProfileInterpreter) { + if (bci != InvocationEntryBci) { + methodDataOop mdo = m->method_data(); + if (mdo != NULL) { + int count = mdo->bci_to_data(branch_bci)->as_JumpData()->taken(); + tty->print_cr("back branch count = %d", count); + } + } + } + } +} + +void NonTieredCompPolicy::trace_osr_request(methodHandle method, nmethod* osr, int bci) { + if (TraceOnStackReplacement) { + ResourceMark rm; + tty->print(osr != NULL ? "Reused OSR entry for " : "Requesting OSR entry for "); + method->print_short_name(tty); + tty->print_cr(" at bci %d", bci); + } +} +#endif // !PRODUCT + // SimpleCompPolicy - compile current method void SimpleCompPolicy::method_invocation_event( methodHandle m, TRAPS) { @@ -137,59 +359,28 @@ void SimpleCompPolicy::method_invocation_event( methodHandle m, TRAPS) { reset_counter_for_invocation_event(m); const char* comment = "count"; - if (!delayCompilationDuringStartup() && canBeCompiled(m) && UseCompiler && CompileBroker::should_compile_new_jobs()) { + if (is_compilation_enabled() && can_be_compiled(m)) { nmethod* nm = m->code(); if (nm == NULL ) { const char* comment = "count"; - CompileBroker::compile_method(m, InvocationEntryBci, + CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_highest_tier, m, hot_count, comment, CHECK); - } else { -#ifdef TIERED - - if (nm->is_compiled_by_c1()) { - const char* comment = "tier1 overflow"; - CompileBroker::compile_method(m, InvocationEntryBci, - m, hot_count, comment, CHECK); - } -#endif // TIERED } } } -void SimpleCompPolicy::method_back_branch_event(methodHandle m, int branch_bci, int loop_top_bci, TRAPS) { +void SimpleCompPolicy::method_back_branch_event(methodHandle m, int bci, TRAPS) { assert(UseCompiler || CompileTheWorld, "UseCompiler should be set by now."); int hot_count = m->backedge_count(); const char* comment = "backedge_count"; - if (!m->is_not_osr_compilable() && !delayCompilationDuringStartup() && canBeCompiled(m) && CompileBroker::should_compile_new_jobs()) { - CompileBroker::compile_method(m, loop_top_bci, m, hot_count, comment, CHECK); - - NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(loop_top_bci));) + if (is_compilation_enabled() && !m->is_not_osr_compilable() && can_be_compiled(m)) { + CompileBroker::compile_method(m, bci, CompLevel_highest_tier, + m, hot_count, comment, CHECK); + NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true));) } } - -int SimpleCompPolicy::compilation_level(methodHandle m, int branch_bci) -{ -#ifdef TIERED - if (!TieredCompilation) { - return CompLevel_highest_tier; - } - if (/* m()->tier1_compile_done() && */ - // QQQ HACK FIX ME set tier1_compile_done!! - !m()->is_native()) { - // Grab the nmethod so it doesn't go away while it's being queried - nmethod* code = m()->code(); - if (code != NULL && code->is_compiled_by_c1()) { - return CompLevel_highest_tier; - } - } - return CompLevel_fast_compile; -#else - return CompLevel_highest_tier; -#endif // TIERED -} - // StackWalkCompPolicy - walk up stack to find a suitable method to compile #ifdef COMPILER2 @@ -204,7 +395,7 @@ void StackWalkCompPolicy::method_invocation_event(methodHandle m, TRAPS) { reset_counter_for_invocation_event(m); const char* comment = "count"; - if (m->code() == NULL && !delayCompilationDuringStartup() && canBeCompiled(m) && UseCompiler && CompileBroker::should_compile_new_jobs()) { + if (is_compilation_enabled() && m->code() == NULL && can_be_compiled(m)) { ResourceMark rm(THREAD); JavaThread *thread = (JavaThread*)THREAD; frame fr = thread->last_frame(); @@ -224,10 +415,6 @@ void StackWalkCompPolicy::method_invocation_event(methodHandle m, TRAPS) { if (first->top_method()->code() != NULL) { // called obsolete method/nmethod -- no need to recompile if (TraceCompilationPolicy) tty->print_cr(" --> " INTPTR_FORMAT, first->top_method()->code()); - } else if (compilation_level(m, InvocationEntryBci) == CompLevel_fast_compile) { - // Tier1 compilation policy avaoids stack walking. - CompileBroker::compile_method(m, InvocationEntryBci, - m, hot_count, comment, CHECK); } else { if (TimeCompilationPolicy) accumulated_time()->start(); GrowableArray* stack = new GrowableArray(50); @@ -236,53 +423,25 @@ void StackWalkCompPolicy::method_invocation_event(methodHandle m, TRAPS) { if (TimeCompilationPolicy) accumulated_time()->stop(); assert(top != NULL, "findTopInlinableFrame returned null"); if (TraceCompilationPolicy) top->print(); - CompileBroker::compile_method(top->top_method(), InvocationEntryBci, + CompileBroker::compile_method(top->top_method(), InvocationEntryBci, CompLevel_highest_tier, m, hot_count, comment, CHECK); } } } -void StackWalkCompPolicy::method_back_branch_event(methodHandle m, int branch_bci, int loop_top_bci, TRAPS) { +void StackWalkCompPolicy::method_back_branch_event(methodHandle m, int bci, TRAPS) { assert(UseCompiler || CompileTheWorld, "UseCompiler should be set by now."); int hot_count = m->backedge_count(); const char* comment = "backedge_count"; - if (!m->is_not_osr_compilable() && !delayCompilationDuringStartup() && canBeCompiled(m) && CompileBroker::should_compile_new_jobs()) { - CompileBroker::compile_method(m, loop_top_bci, m, hot_count, comment, CHECK); + if (is_compilation_enabled() && !m->is_not_osr_compilable() && can_be_compiled(m)) { + CompileBroker::compile_method(m, bci, CompLevel_highest_tier, m, hot_count, comment, CHECK); - NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(loop_top_bci));) + NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true));) } } -int StackWalkCompPolicy::compilation_level(methodHandle m, int osr_bci) -{ - int comp_level = CompLevel_full_optimization; - if (TieredCompilation && osr_bci == InvocationEntryBci) { - if (CompileTheWorld) { - // Under CTW, the first compile is tier1, the second tier2 - if (m->highest_tier_compile() == CompLevel_none) { - comp_level = CompLevel_fast_compile; - } - } else if (!m->has_osr_nmethod()) { - // Before tier1 is done, use invocation_count + backedge_count to - // compare against the threshold. After that, the counters may/will - // be reset, so rely on the straight interpreter_invocation_count. - if (m->highest_tier_compile() == CompLevel_initial_compile) { - if (m->interpreter_invocation_count() < Tier2CompileThreshold) { - comp_level = CompLevel_fast_compile; - } - } else if (m->invocation_count() + m->backedge_count() < - Tier2CompileThreshold) { - comp_level = CompLevel_fast_compile; - } - } - - } - return comp_level; -} - - RFrame* StackWalkCompPolicy::findTopInlinableFrame(GrowableArray* stack) { // go up the stack until finding a frame that (probably) won't be inlined // into its caller @@ -372,7 +531,7 @@ RFrame* StackWalkCompPolicy::findTopInlinableFrame(GrowableArray* stack // If the caller method is too big or something then we do not want to // compile it just to inline a method - if (!canBeCompiled(next_m)) { + if (!can_be_compiled(next_m)) { msg = "caller cannot be compiled"; break; } @@ -439,7 +598,7 @@ const char* StackWalkCompPolicy::shouldNotInline(methodHandle m) { if (!instanceKlass::cast(m->method_holder())->is_initialized()) return (_msg = "method holder not initialized"); if (m->is_native()) return (_msg = "native method"); nmethod* m_code = m->code(); - if( m_code != NULL && m_code->instructions_size() > InlineSmallCode ) + if (m_code != NULL && m_code->code_size() > InlineSmallCode) return (_msg = "already compiled into a big method"); // use frequency-based objections only for non-trivial methods diff --git a/hotspot/src/share/vm/runtime/compilationPolicy.hpp b/hotspot/src/share/vm/runtime/compilationPolicy.hpp index 3a58f27c7b2..9000467eee6 100644 --- a/hotspot/src/share/vm/runtime/compilationPolicy.hpp +++ b/hotspot/src/share/vm/runtime/compilationPolicy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,53 +25,91 @@ // The CompilationPolicy selects which method (if any) should be compiled. // It also decides which methods must always be compiled (i.e., are never // interpreted). +class CompileTask; +class CompileQueue; class CompilationPolicy : public CHeapObj { - private: static CompilationPolicy* _policy; // Accumulated time static elapsedTimer _accumulated_time; static bool _in_vm_startup; - - public: - virtual void method_invocation_event(methodHandle m, TRAPS) = 0; - virtual void method_back_branch_event(methodHandle m, int branch_bci, int loop_top_bci, TRAPS) = 0; - virtual int compilation_level(methodHandle m, int branch_bci) = 0; - - void reset_counter_for_invocation_event(methodHandle method); - void reset_counter_for_back_branch_event(methodHandle method); - +public: static void set_in_vm_startup(bool in_vm_startup) { _in_vm_startup = in_vm_startup; } static void completed_vm_startup(); - static bool delayCompilationDuringStartup() { return _in_vm_startup; } - - static bool mustBeCompiled(methodHandle m); // m must be compiled before executing it - static bool canBeCompiled(methodHandle m); // m is allowed to be compiled + static bool delay_compilation_during_startup() { return _in_vm_startup; } + // m must be compiled before executing it + static bool must_be_compiled(methodHandle m, int comp_level = CompLevel_all); + // m is allowed to be compiled + static bool can_be_compiled(methodHandle m, int comp_level = CompLevel_all); + static bool is_compilation_enabled(); static void set_policy(CompilationPolicy* policy) { _policy = policy; } - static CompilationPolicy* policy() { return _policy; } + static CompilationPolicy* policy() { return _policy; } // Profiling elapsedTimer* accumulated_time() { return &_accumulated_time; } void print_time() PRODUCT_RETURN; + virtual int compiler_count(CompLevel comp_level) = 0; + // main notification entry, return a pointer to an nmethod if the OSR is required, + // returns NULL otherwise. + virtual nmethod* event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, TRAPS) = 0; + // safepoint() is called at the end of the safepoint + virtual void do_safepoint_work() = 0; + // reprofile request + virtual void reprofile(ScopeDesc* trap_scope, bool is_osr) = 0; + // delay_compilation(method) can be called by any component of the runtime to notify the policy + // that it's recommended to delay the complation of this method. + virtual void delay_compilation(methodOop method) = 0; + // disable_compilation() is called whenever the runtime decides to disable compilation of the + // specified method. + virtual void disable_compilation(methodOop method) = 0; + // Select task is called by CompileBroker. The queue is guaranteed to have at least one + // element and is locked. The function should select one and return it. + virtual CompileTask* select_task(CompileQueue* compile_queue) = 0; + // Tell the runtime if we think a given method is adequately profiled. + virtual bool is_mature(methodOop method) = 0; + // Do policy initialization + virtual void initialize() = 0; }; -class SimpleCompPolicy : public CompilationPolicy { +// A base class for baseline policies. +class NonTieredCompPolicy : public CompilationPolicy { + int _compiler_count; +protected: + static void trace_frequency_counter_overflow(methodHandle m, int branch_bci, int bci); + static void trace_osr_request(methodHandle method, nmethod* osr, int bci); + static void trace_osr_completion(nmethod* osr_nm); + void reset_counter_for_invocation_event(methodHandle method); + void reset_counter_for_back_branch_event(methodHandle method); +public: + NonTieredCompPolicy() : _compiler_count(0) { } + virtual int compiler_count(CompLevel comp_level); + virtual void do_safepoint_work(); + virtual void reprofile(ScopeDesc* trap_scope, bool is_osr); + virtual void delay_compilation(methodOop method); + virtual void disable_compilation(methodOop method); + virtual bool is_mature(methodOop method); + virtual void initialize(); + virtual CompileTask* select_task(CompileQueue* compile_queue); + virtual nmethod* event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, TRAPS); + virtual void method_invocation_event(methodHandle m, TRAPS) = 0; + virtual void method_back_branch_event(methodHandle m, int bci, TRAPS) = 0; +}; + +class SimpleCompPolicy : public NonTieredCompPolicy { public: - void method_invocation_event( methodHandle m, TRAPS); - void method_back_branch_event(methodHandle m, int branch_bci, int loop_top_bci, TRAPS); - int compilation_level(methodHandle m, int branch_bci); + virtual void method_invocation_event(methodHandle m, TRAPS); + virtual void method_back_branch_event(methodHandle m, int bci, TRAPS); }; // StackWalkCompPolicy - existing C2 policy #ifdef COMPILER2 -class StackWalkCompPolicy : public CompilationPolicy { +class StackWalkCompPolicy : public NonTieredCompPolicy { public: - void method_invocation_event(methodHandle m, TRAPS); - void method_back_branch_event(methodHandle m, int branch_bci, int loop_top_bci, TRAPS); - int compilation_level(methodHandle m, int branch_bci); + virtual void method_invocation_event(methodHandle m, TRAPS); + virtual void method_back_branch_event(methodHandle m, int bci, TRAPS); private: RFrame* findTopInlinableFrame(GrowableArray* stack); diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index 2fc5edc360d..2cc90961799 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -1301,7 +1301,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra bool update_trap_state = true; bool make_not_entrant = false; bool make_not_compilable = false; - bool reset_counters = false; + bool reprofile = false; switch (action) { case Action_none: // Keep the old code. @@ -1328,7 +1328,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra // had been traps taken from compiled code. This will update // the MDO trap history so that the next compilation will // properly detect hot trap sites. - reset_counters = true; + reprofile = true; break; case Action_make_not_entrant: // Request immediate recompilation, and get rid of the old code. @@ -1422,7 +1422,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra // this trap point already, run the method in the interpreter // for a while to exercise it more thoroughly. if (make_not_entrant && maybe_prior_recompile && maybe_prior_trap) { - reset_counters = true; + reprofile = true; } } @@ -1452,24 +1452,21 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra if (trap_method() == nm->method()) { make_not_compilable = true; } else { - trap_method->set_not_compilable(); + trap_method->set_not_compilable(CompLevel_full_optimization); // But give grace to the enclosing nm->method(). } } } - // Reset invocation counters - if (reset_counters) { - if (nm->is_osr_method()) - reset_invocation_counter(trap_scope, CompileThreshold); - else - reset_invocation_counter(trap_scope); + // Reprofile + if (reprofile) { + CompilationPolicy::policy()->reprofile(trap_scope, nm->is_osr_method()); } // Give up compiling - if (make_not_compilable && !nm->method()->is_not_compilable()) { + if (make_not_compilable && !nm->method()->is_not_compilable(CompLevel_full_optimization)) { assert(make_not_entrant, "consistent"); - nm->method()->set_not_compilable(); + nm->method()->set_not_compilable(CompLevel_full_optimization); } } // Free marked resources @@ -1569,22 +1566,6 @@ Deoptimization::update_method_data_from_interpreter(methodDataHandle trap_mdo, i ignore_maybe_prior_recompile); } -void Deoptimization::reset_invocation_counter(ScopeDesc* trap_scope, jint top_count) { - ScopeDesc* sd = trap_scope; - for (; !sd->is_top(); sd = sd->sender()) { - // Reset ICs of inlined methods, since they can trigger compilations also. - sd->method()->invocation_counter()->reset(); - } - InvocationCounter* c = sd->method()->invocation_counter(); - if (top_count != _no_count) { - // It was an OSR method, so bump the count higher. - c->set(c->state(), top_count); - } else { - c->reset(); - } - sd->method()->backedge_counter()->reset(); -} - Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, jint trap_request) { // Still in Java no safepoints diff --git a/hotspot/src/share/vm/runtime/deoptimization.hpp b/hotspot/src/share/vm/runtime/deoptimization.hpp index cb6cf7b5e6e..83bccfd3fc5 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.hpp +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp @@ -311,12 +311,6 @@ class Deoptimization : AllStatic { static void popframe_preserve_args(JavaThread* thread, int bytes_to_save, void* start_address); private: - enum { - _no_count = -1 - }; - - static void reset_invocation_counter(ScopeDesc* trap_scope, jint count = _no_count); - static methodDataOop get_method_data(JavaThread* thread, methodHandle m, bool create_if_missing); // Update the mdo's count and per-BCI reason bits, returning previous state: static ProfileData* query_update_method_data(methodDataHandle trap_mdo, diff --git a/hotspot/src/share/vm/runtime/dtraceJSDT.cpp b/hotspot/src/share/vm/runtime/dtraceJSDT.cpp index a569b2f0681..06bc8a97304 100644 --- a/hotspot/src/share/vm/runtime/dtraceJSDT.cpp +++ b/hotspot/src/share/vm/runtime/dtraceJSDT.cpp @@ -65,7 +65,7 @@ jlong DTraceJSDT::activate( THROW_MSG_0(vmSymbols::java_lang_RuntimeException(), "Unable to register DTrace probes (CodeCache: no room for DTrace nmethods)."); } - h_method()->set_not_compilable(CompLevel_highest_tier); + h_method()->set_not_compilable(); h_method()->set_code(h_method, nm); probes->nmethod_at_put(count++, nm); } diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index 89de3ca1a99..bf24d6eb843 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -215,17 +215,15 @@ bool frame::can_be_deoptimized() const { return !nm->is_at_poll_return(pc()); } -void frame::deoptimize(JavaThread* thread, bool thread_is_known_safe) { -// Schedule deoptimization of an nmethod activation with this frame. - - // Store the original pc before an patch (or request to self-deopt) - // in the published location of the frame. - +void frame::deoptimize(JavaThread* thread) { + // Schedule deoptimization of an nmethod activation with this frame. assert(_cb != NULL && _cb->is_nmethod(), "must be"); nmethod* nm = (nmethod*)_cb; // This is a fix for register window patching race - if (NeedsDeoptSuspend && !thread_is_known_safe) { + if (NeedsDeoptSuspend && Thread::current() != thread) { + assert(SafepointSynchronize::is_at_safepoint(), + "patching other threads for deopt may only occur at a safepoint"); // It is possible especially with DeoptimizeALot/DeoptimizeRandom that // we could see the frame again and ask for it to be deoptimized since @@ -248,7 +246,11 @@ void frame::deoptimize(JavaThread* thread, bool thread_is_known_safe) { // whether to spin or block. It isn't worth it. Just treat it like // native and be done with it. // - JavaThreadState state = thread->thread_state(); + // Examine the state of the thread at the start of safepoint since + // threads that were in native at the start of the safepoint could + // come to a halt during the safepoint, changing the current value + // of the safepoint_state. + JavaThreadState state = thread->safepoint_state()->orig_thread_state(); if (state == _thread_in_native || state == _thread_in_native_trans) { // Since we are at a safepoint the target thread will stop itself // before it can return to java as long as we remain at the safepoint. @@ -535,8 +537,8 @@ void frame::print_value_on(outputStream* st, JavaThread *thread) const { st->cr(); #ifndef PRODUCT if (end == NULL) { - begin = _cb->instructions_begin(); - end = _cb->instructions_end(); + begin = _cb->code_begin(); + end = _cb->code_end(); } #endif } diff --git a/hotspot/src/share/vm/runtime/frame.hpp b/hotspot/src/share/vm/runtime/frame.hpp index 4f2df2ad964..a2ac51f3669 100644 --- a/hotspot/src/share/vm/runtime/frame.hpp +++ b/hotspot/src/share/vm/runtime/frame.hpp @@ -174,7 +174,7 @@ class frame VALUE_OBJ_CLASS_SPEC { address sender_pc() const; // Support for deoptimization - void deoptimize(JavaThread* thread, bool thread_is_known_safe = false); + void deoptimize(JavaThread* thread); // The frame's original SP, before any extension by an interpreted callee; // used for packing debug info into vframeArray objects and vframeArray lookup. diff --git a/hotspot/src/share/vm/runtime/globals.cpp b/hotspot/src/share/vm/runtime/globals.cpp index e0603d38d6a..eb896c083f7 100644 --- a/hotspot/src/share/vm/runtime/globals.cpp +++ b/hotspot/src/share/vm/runtime/globals.cpp @@ -68,30 +68,38 @@ bool Flag::is_external() const { // Length of format string (e.g. "%.1234s") for printing ccstr below #define FORMAT_BUFFER_LEN 16 -void Flag::print_on(outputStream* st) { - st->print("%5s %-35s %c= ", type, name, (origin != DEFAULT ? ':' : ' ')); +void Flag::print_on(outputStream* st, bool withComments) { + st->print("%9s %-40s %c= ", type, name, (origin != DEFAULT ? ':' : ' ')); if (is_bool()) st->print("%-16s", get_bool() ? "true" : "false"); if (is_intx()) st->print("%-16ld", get_intx()); if (is_uintx()) st->print("%-16lu", get_uintx()); if (is_uint64_t()) st->print("%-16lu", get_uint64_t()); + if (is_double()) st->print("%-16f", get_double()); + if (is_ccstr()) { - const char* cp = get_ccstr(); - if (cp != NULL) { - const char* eol; - while ((eol = strchr(cp, '\n')) != NULL) { - char format_buffer[FORMAT_BUFFER_LEN]; - size_t llen = pointer_delta(eol, cp, sizeof(char)); - jio_snprintf(format_buffer, FORMAT_BUFFER_LEN, + const char* cp = get_ccstr(); + if (cp != NULL) { + const char* eol; + while ((eol = strchr(cp, '\n')) != NULL) { + char format_buffer[FORMAT_BUFFER_LEN]; + size_t llen = pointer_delta(eol, cp, sizeof(char)); + jio_snprintf(format_buffer, FORMAT_BUFFER_LEN, "%%." SIZE_FORMAT "s", llen); - st->print(format_buffer, cp); - st->cr(); - cp = eol+1; - st->print("%5s %-35s += ", "", name); - } - st->print("%-16s", cp); - } + st->print(format_buffer, cp); + st->cr(); + cp = eol+1; + st->print("%5s %-35s += ", "", name); + } + st->print("%-16s", cp); + } + else st->print("%-16s", ""); + } + st->print("%-20s", kind); + if (withComments) { +#ifndef PRODUCT + st->print("%s", doc ); +#endif } - st->print(" %s", kind); st->cr(); } @@ -131,67 +139,67 @@ void Flag::print_as_flag(outputStream* st) { // 4991491 do not "optimize out" the was_set false values: omitting them // tickles a Microsoft compiler bug causing flagTable to be malformed -#define RUNTIME_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{product}", DEFAULT }, -#define RUNTIME_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{pd product}", DEFAULT }, -#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{diagnostic}", DEFAULT }, -#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{experimental}", DEFAULT }, -#define RUNTIME_MANAGEABLE_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{manageable}", DEFAULT }, -#define RUNTIME_PRODUCT_RW_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{product rw}", DEFAULT }, +#define RUNTIME_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{product}", DEFAULT }, +#define RUNTIME_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{pd product}", DEFAULT }, +#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{diagnostic}", DEFAULT }, +#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{experimental}", DEFAULT }, +#define RUNTIME_MANAGEABLE_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{manageable}", DEFAULT }, +#define RUNTIME_PRODUCT_RW_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{product rw}", DEFAULT }, #ifdef PRODUCT #define RUNTIME_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #define RUNTIME_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ #define RUNTIME_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) #else - #define RUNTIME_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "", DEFAULT }, - #define RUNTIME_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{pd}", DEFAULT }, - #define RUNTIME_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{notproduct}", DEFAULT }, + #define RUNTIME_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "", DEFAULT }, + #define RUNTIME_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{pd}", DEFAULT }, + #define RUNTIME_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{notproduct}", DEFAULT }, #endif #ifdef _LP64 - #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{lp64_product}", DEFAULT }, + #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{lp64_product}", DEFAULT }, #else #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #endif // _LP64 -#define C1_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C1 product}", DEFAULT }, -#define C1_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C1 pd product}", DEFAULT }, +#define C1_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 product}", DEFAULT }, +#define C1_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 pd product}", DEFAULT }, #ifdef PRODUCT #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ #define C1_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) #else - #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C1}", DEFAULT }, - #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C1 pd}", DEFAULT }, - #define C1_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C1 notproduct}", DEFAULT }, + #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C1}", DEFAULT }, + #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{C1 pd}", DEFAULT }, + #define C1_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C1 notproduct}", DEFAULT }, #endif -#define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 product}", DEFAULT }, -#define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C2 pd product}", DEFAULT }, -#define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 diagnostic}", DEFAULT }, -#define C2_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 experimental}", DEFAULT }, +#define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 product}", DEFAULT }, +#define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 pd product}", DEFAULT }, +#define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 diagnostic}", DEFAULT }, +#define C2_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 experimental}", DEFAULT }, #ifdef PRODUCT #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) #else - #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2}", DEFAULT }, - #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C2 pd}", DEFAULT }, - #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 notproduct}", DEFAULT }, + #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C2}", DEFAULT }, + #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{C2 pd}", DEFAULT }, + #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C2 notproduct}", DEFAULT }, #endif -#define SHARK_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark product}", DEFAULT }, -#define SHARK_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{Shark pd product}", DEFAULT }, -#define SHARK_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark diagnostic}", DEFAULT }, +#define SHARK_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark product}", DEFAULT }, +#define SHARK_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark pd product}", DEFAULT }, +#define SHARK_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark diagnostic}", DEFAULT }, #ifdef PRODUCT #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) #else - #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark}", DEFAULT }, - #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{Shark pd}", DEFAULT }, - #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark notproduct}", DEFAULT }, + #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{Shark}", DEFAULT }, + #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{Shark pd}", DEFAULT }, + #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{Shark notproduct}", DEFAULT }, #endif static Flag flagTable[] = { @@ -485,7 +493,7 @@ void CommandLineFlags::verify() { #endif // PRODUCT -void CommandLineFlags::printFlags() { +void CommandLineFlags::printFlags(bool withComments) { // Print the flags sorted by name // note: this method is called before the thread structure is in place // which means resource allocation cannot be used. @@ -505,7 +513,7 @@ void CommandLineFlags::printFlags() { tty->print_cr("[Global flags]"); for (int i = 0; i < length; i++) { if (array[i]->is_unlocked()) { - array[i]->print_on(tty); + array[i]->print_on(tty, withComments); } } FREE_C_HEAP_ARRAY(Flag*, array); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 28b26381fba..1fe8eb9a36b 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -35,14 +35,7 @@ define_pd_global(bool, ProfileTraps, false); define_pd_global(bool, TieredCompilation, false); define_pd_global(intx, CompileThreshold, 0); -define_pd_global(intx, Tier2CompileThreshold, 0); -define_pd_global(intx, Tier3CompileThreshold, 0); -define_pd_global(intx, Tier4CompileThreshold, 0); - define_pd_global(intx, BackEdgeThreshold, 0); -define_pd_global(intx, Tier2BackEdgeThreshold, 0); -define_pd_global(intx, Tier3BackEdgeThreshold, 0); -define_pd_global(intx, Tier4BackEdgeThreshold, 0); define_pd_global(intx, OnStackReplacePercentage, 0); define_pd_global(bool, ResizeTLAB, false); @@ -90,6 +83,9 @@ struct Flag { const char *type; const char *name; void* addr; + + NOT_PRODUCT(const char *doc;) + const char *kind; FlagValueOrigin origin; @@ -131,7 +127,7 @@ struct Flag { bool is_writeable() const; bool is_external() const; - void print_on(outputStream* st); + void print_on(outputStream* st, bool withComments = false ); void print_as_flag(outputStream* st); }; @@ -211,7 +207,7 @@ class CommandLineFlags { static bool wasSetOnCmdline(const char* name, bool* value); static void printSetFlags(); - static void printFlags(); + static void printFlags(bool withComments = false ); static void verify() PRODUCT_RETURN; }; @@ -1541,13 +1537,13 @@ class CommandLineFlags { "Use BinaryTreeDictionary as default in the CMS generation") \ \ product(uintx, CMSIndexedFreeListReplenish, 4, \ - "Replenish and indexed free list with this number of chunks") \ + "Replenish an indexed free list with this number of chunks") \ \ product(bool, CMSReplenishIntermediate, true, \ "Replenish all intermediate free-list caches") \ \ product(bool, CMSSplitIndexedFreeListBlocks, true, \ - "When satisfying batched demand, splot blocks from the " \ + "When satisfying batched demand, split blocks from the " \ "IndexedFreeList whose size is a multiple of requested size") \ \ product(bool, CMSLoopWarn, false, \ @@ -1712,7 +1708,7 @@ class CommandLineFlags { develop(bool, VerifyBlockOffsetArray, false, \ "Do (expensive!) block offset array verification") \ \ - product(bool, BlockOffsetArrayUseUnallocatedBlock, trueInDebug, \ + product(bool, BlockOffsetArrayUseUnallocatedBlock, false, \ "Maintain _unallocated_block in BlockOffsetArray" \ " (currently applicable only to CMS collector)") \ \ @@ -1971,7 +1967,7 @@ class CommandLineFlags { product(uintx, TenuredGenerationSizeSupplementDecay, 2, \ "Decay factor to TenuredGenerationSizeIncrement") \ \ - product(uintx, MaxGCPauseMillis, max_uintx, \ + product(uintx, MaxGCPauseMillis, max_uintx, \ "Adaptive size policy maximum GC pause time goal in msec, " \ "or (G1 Only) the max. GC time per MMU time slice") \ \ @@ -2366,9 +2362,6 @@ class CommandLineFlags { develop(bool, EagerInitialization, false, \ "Eagerly initialize classes if possible") \ \ - product(bool, Tier1UpdateMethodData, trueInTiered, \ - "Update methodDataOops in Tier1-generated code") \ - \ develop(bool, TraceMethodReplacement, false, \ "Print when methods are replaced do to recompilation") \ \ @@ -2406,6 +2399,9 @@ class CommandLineFlags { product(bool, PrintFlagsFinal, false, \ "Print all VM flags after argument and ergonomic processing") \ \ + notproduct(bool, PrintFlagsWithComments, false, \ + "Print all VM flags with default values and descriptions and exit")\ + \ diagnostic(bool, SerializeVMOutput, true, \ "Use a mutex to serialize output to tty and hotspot.log") \ \ @@ -2476,6 +2472,9 @@ class CommandLineFlags { develop(bool, MonomorphicArrayCheck, true, \ "Uncommon-trap array store checks that require full type check") \ \ + diagnostic(bool, ProfileDynamicTypes, true, \ + "do extra type profiling and use it more aggressively") \ + \ develop(bool, DelayCompilationDuringStartup, true, \ "Delay invoking the compiler until main application class is " \ "loaded") \ @@ -2895,7 +2894,7 @@ class CommandLineFlags { "if non-zero, start verifying C heap after Nth call to " \ "malloc/realloc/free") \ \ - product(intx, TypeProfileWidth, 2, \ + product(intx, TypeProfileWidth, 2, \ "number of receiver types to record in call/cast profile") \ \ develop(intx, BciProfileWidth, 2, \ @@ -3092,10 +3091,6 @@ class CommandLineFlags { \ product(intx, SafepointSpinBeforeYield, 2000, "(Unstable)") \ \ - product(bool, UseDepthFirstScavengeOrder, true, \ - "true: the scavenge order will be depth-first, " \ - "false: the scavenge order will be breadth-first") \ - \ product(bool, PSChunkLargeArrays, true, \ "true: process large arrays in chunks") \ \ @@ -3307,30 +3302,98 @@ class CommandLineFlags { product_pd(intx, BackEdgeThreshold, \ "Interpreter Back edge threshold at which an OSR compilation is invoked")\ \ - product(intx, Tier1BytecodeLimit, 10, \ - "Must have at least this many bytecodes before tier1" \ - "invocation counters are used") \ + product(intx, Tier0InvokeNotifyFreqLog, 7, \ + "Interpreter (tier 0) invocation notification frequency.") \ \ - product_pd(intx, Tier2CompileThreshold, \ - "threshold at which a tier 2 compilation is invoked") \ + product(intx, Tier2InvokeNotifyFreqLog, 11, \ + "C1 without MDO (tier 2) invocation notification frequency.") \ \ - product_pd(intx, Tier2BackEdgeThreshold, \ - "Back edge threshold at which a tier 2 compilation is invoked") \ + product(intx, Tier3InvokeNotifyFreqLog, 10, \ + "C1 with MDO profiling (tier 3) invocation notification " \ + "frequency.") \ \ - product_pd(intx, Tier3CompileThreshold, \ - "threshold at which a tier 3 compilation is invoked") \ + product(intx, Tier0BackedgeNotifyFreqLog, 10, \ + "Interpreter (tier 0) invocation notification frequency.") \ \ - product_pd(intx, Tier3BackEdgeThreshold, \ - "Back edge threshold at which a tier 3 compilation is invoked") \ + product(intx, Tier2BackedgeNotifyFreqLog, 14, \ + "C1 without MDO (tier 2) invocation notification frequency.") \ \ - product_pd(intx, Tier4CompileThreshold, \ - "threshold at which a tier 4 compilation is invoked") \ + product(intx, Tier3BackedgeNotifyFreqLog, 13, \ + "C1 with MDO profiling (tier 3) invocation notification " \ + "frequency.") \ \ - product_pd(intx, Tier4BackEdgeThreshold, \ - "Back edge threshold at which a tier 4 compilation is invoked") \ + product(intx, Tier2CompileThreshold, 0, \ + "threshold at which tier 2 compilation is invoked") \ + \ + product(intx, Tier2BackEdgeThreshold, 0, \ + "Back edge threshold at which tier 2 compilation is invoked") \ + \ + product(intx, Tier3InvocationThreshold, 200, \ + "Compile if number of method invocations crosses this " \ + "threshold") \ + \ + product(intx, Tier3MinInvocationThreshold, 100, \ + "Minimum invocation to compile at tier 3") \ + \ + product(intx, Tier3CompileThreshold, 2000, \ + "Threshold at which tier 3 compilation is invoked (invocation " \ + "minimum must be satisfied.") \ + \ + product(intx, Tier3BackEdgeThreshold, 7000, \ + "Back edge threshold at which tier 3 OSR compilation is invoked") \ + \ + product(intx, Tier4InvocationThreshold, 5000, \ + "Compile if number of method invocations crosses this " \ + "threshold") \ + \ + product(intx, Tier4MinInvocationThreshold, 600, \ + "Minimum invocation to compile at tier 4") \ + \ + product(intx, Tier4CompileThreshold, 15000, \ + "Threshold at which tier 4 compilation is invoked (invocation " \ + "minimum must be satisfied.") \ + \ + product(intx, Tier4BackEdgeThreshold, 40000, \ + "Back edge threshold at which tier 4 OSR compilation is invoked") \ + \ + product(intx, Tier3DelayOn, 5, \ + "If C2 queue size grows over this amount per compiler thread " \ + "stop compiling at tier 3 and start compiling at tier 2") \ + \ + product(intx, Tier3DelayOff, 2, \ + "If C2 queue size is less than this amount per compiler thread " \ + "allow methods compiled at tier 2 transition to tier 3") \ + \ + product(intx, Tier3LoadFeedback, 5, \ + "Tier 3 thresholds will increase twofold when C1 queue size " \ + "reaches this amount per compiler thread") \ + \ + product(intx, Tier4LoadFeedback, 3, \ + "Tier 4 thresholds will increase twofold when C2 queue size " \ + "reaches this amount per compiler thread") \ + \ + product(intx, TieredCompileTaskTimeout, 50, \ + "Kill compile task if method was not used within " \ + "given timeout in milliseconds") \ + \ + product(intx, TieredStopAtLevel, 4, \ + "Stop at given compilation level") \ + \ + product(intx, Tier0ProfilingStartPercentage, 200, \ + "Start profiling in interpreter if the counters exceed tier 3" \ + "thresholds by the specified percentage") \ + \ + product(intx, TieredRateUpdateMinTime, 1, \ + "Minimum rate sampling interval (in milliseconds)") \ + \ + product(intx, TieredRateUpdateMaxTime, 25, \ + "Maximum rate sampling interval (in milliseconds)") \ \ product_pd(bool, TieredCompilation, \ - "Enable two-tier compilation") \ + "Enable tiered compilation") \ + \ + product(bool, PrintTieredEvents, false, \ + "Print tiered events notifications") \ \ product(bool, StressTieredRuntime, false, \ "Alternate client and server compiler on compile requests") \ diff --git a/hotspot/src/share/vm/runtime/icache.cpp b/hotspot/src/share/vm/runtime/icache.cpp index 5774f0d28ed..78a3bcd7808 100644 --- a/hotspot/src/share/vm/runtime/icache.cpp +++ b/hotspot/src/share/vm/runtime/icache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ void AbstractICache::initialize() { ResourceMark rm; BufferBlob* b = BufferBlob::create("flush_icache_stub", ICache::stub_size); - CodeBuffer c(b->instructions_begin(), b->instructions_size()); + CodeBuffer c(b); ICacheStubGenerator g(&c); g.generate_icache_flush(&_flush_icache_stub); diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp index df3a8bd46dc..9eac44347c2 100644 --- a/hotspot/src/share/vm/runtime/init.cpp +++ b/hotspot/src/share/vm/runtime/init.cpp @@ -128,6 +128,12 @@ jint init_globals() { Universe::verify(); // make sure we're starting with a clean slate } + // All the flags that get adjusted by VM_Version_init and os::init_2 + // have been set so dump the flags now. + if (PrintFlagsFinal) { + CommandLineFlags::printFlags(); + } + return JNI_OK; } diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index b831a0fcb3d..726c96be94e 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -198,7 +198,7 @@ void print_statistics() { if (CountCompiledCalls) { print_method_invocation_histogram(); } - if (ProfileInterpreter || Tier1UpdateMethodData) { + if (ProfileInterpreter || C1UpdateMethodData) { print_method_profiling_data(); } if (TimeCompiler) { diff --git a/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 0971a076e45..3d1c41ca6b4 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -329,9 +329,10 @@ void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArgument assert(!thread->is_Compiler_thread(), "cannot compile from the compiler"); - if (CompilationPolicy::mustBeCompiled(method)) { + if (CompilationPolicy::must_be_compiled(method)) { CompileBroker::compile_method(method, InvocationEntryBci, - methodHandle(), 0, "mustBeCompiled", CHECK); + CompLevel_initial_compile, + methodHandle(), 0, "must_be_compiled", CHECK); } // Since the call stub sets up like the interpreter we call the from_interpreted_entry diff --git a/hotspot/src/share/vm/runtime/orderAccess.cpp b/hotspot/src/share/vm/runtime/orderAccess.cpp index b61c481607e..12124f964ba 100644 --- a/hotspot/src/share/vm/runtime/orderAccess.cpp +++ b/hotspot/src/share/vm/runtime/orderAccess.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,6 @@ # include "incls/_precompiled.incl" # include "incls/_orderAccess.cpp.incl" -volatile intptr_t OrderAccess::dummy = 0; - void OrderAccess::StubRoutines_fence() { // Use a stub if it exists. It may not exist during bootstrap so do // nothing in that case but assert if no fence code exists after threads have been created diff --git a/hotspot/src/share/vm/runtime/orderAccess.hpp b/hotspot/src/share/vm/runtime/orderAccess.hpp index 42c9227f5a2..28b049a43fc 100644 --- a/hotspot/src/share/vm/runtime/orderAccess.hpp +++ b/hotspot/src/share/vm/runtime/orderAccess.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -166,6 +166,12 @@ // and release must include a sequence point, usually via a volatile memory // access. Other ways to guarantee a sequence point are, e.g., use of // indirect calls and linux's __asm__ volatile. +// Note: as of 6973570, we have replaced the originally static "dummy" field +// (see above) by a volatile store to the stack. All of the versions of the +// compilers that we currently use (SunStudio, gcc and VC++) respect the +// semantics of volatile here. If you build HotSpot using other +// compilers, you may need to verify that no compiler reordering occurs +// across the sequence point respresented by the volatile access. // // // os::is_MP Considered Redundant @@ -297,10 +303,6 @@ class OrderAccess : AllStatic { static void release_store_ptr_fence(volatile intptr_t* p, intptr_t v); static void release_store_ptr_fence(volatile void* p, void* v); - // In order to force a memory access, implementations may - // need a volatile externally visible dummy variable. - static volatile intptr_t dummy; - private: // This is a helper that invokes the StubRoutines::fence_entry() // routine if it exists, It should only be used by platforms that diff --git a/hotspot/src/share/vm/runtime/rframe.cpp b/hotspot/src/share/vm/runtime/rframe.cpp index e9125796d25..ca7501ab493 100644 --- a/hotspot/src/share/vm/runtime/rframe.cpp +++ b/hotspot/src/share/vm/runtime/rframe.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,7 +120,7 @@ int InterpretedRFrame::cost() const { int CompiledRFrame::cost() const { nmethod* nm = top_method()->code(); if (nm != NULL) { - return nm->code_size(); + return nm->insts_size(); } else { return top_method()->code_size(); } diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp index 65d130de103..e1a1d432ec2 100644 --- a/hotspot/src/share/vm/runtime/safepoint.cpp +++ b/hotspot/src/share/vm/runtime/safepoint.cpp @@ -430,29 +430,7 @@ bool SafepointSynchronize::is_cleanup_needed() { return false; } -jlong CounterDecay::_last_timestamp = 0; -static void do_method(methodOop m) { - m->invocation_counter()->decay(); -} - -void CounterDecay::decay() { - _last_timestamp = os::javaTimeMillis(); - - // This operation is going to be performed only at the end of a safepoint - // and hence GC's will not be going on, all Java mutators are suspended - // at this point and hence SystemDictionary_lock is also not needed. - assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint"); - int nclasses = SystemDictionary::number_of_classes(); - double classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 / - CounterHalfLifeTime); - for (int i = 0; i < classes_per_tick; i++) { - klassOop k = SystemDictionary::try_get_next_class(); - if (k != NULL && k->klass_part()->oop_is_instance()) { - instanceKlass::cast(k)->methods_do(do_method); - } - } -} // Various cleaning tasks that should be done periodically at safepoints void SafepointSynchronize::do_cleanup_tasks() { @@ -465,10 +443,9 @@ void SafepointSynchronize::do_cleanup_tasks() { TraceTime t2("updating inline caches", TraceSafepointCleanupTime); InlineCacheBuffer::update_inline_caches(); } - - if(UseCounterDecay && CounterDecay::is_decay_needed()) { - TraceTime t3("decaying counter", TraceSafepointCleanupTime); - CounterDecay::decay(); + { + TraceTime t3("compilation policy safepoint handler", TraceSafepointCleanupTime); + CompilationPolicy::policy()->do_safepoint_work(); } TraceTime t4("sweeping nmethods", TraceSafepointCleanupTime); @@ -782,6 +759,9 @@ void ThreadSafepointState::examine_state_of_thread() { JavaThreadState state = _thread->thread_state(); + // Save the state at the start of safepoint processing. + _orig_thread_state = state; + // Check for a thread that is suspended. Note that thread resume tries // to grab the Threads_lock which we own here, so a thread cannot be // resumed during safepoint synchronization. diff --git a/hotspot/src/share/vm/runtime/safepoint.hpp b/hotspot/src/share/vm/runtime/safepoint.hpp index 46d7f3c3b97..92b2805c4c9 100644 --- a/hotspot/src/share/vm/runtime/safepoint.hpp +++ b/hotspot/src/share/vm/runtime/safepoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,6 +147,9 @@ public: static long last_non_safepoint_interval() { return os::javaTimeMillis() - _end_of_last_safepoint; } + static long end_of_last_safepoint() { + return _end_of_last_safepoint; + } static bool is_cleanup_needed(); static void do_cleanup_tasks(); @@ -185,6 +188,7 @@ class ThreadSafepointState: public CHeapObj { JavaThread * _thread; volatile suspend_type _type; + JavaThreadState _orig_thread_state; public: @@ -199,6 +203,7 @@ class ThreadSafepointState: public CHeapObj { JavaThread* thread() const { return _thread; } suspend_type type() const { return _type; } bool is_running() const { return (_type==_running); } + JavaThreadState orig_thread_state() const { return _orig_thread_state; } // Support for safepoint timeout (debugging) bool has_called_back() const { return _has_called_back; } @@ -226,15 +231,4 @@ class ThreadSafepointState: public CHeapObj { } }; -// -// CounterDecay -// -// Interates through invocation counters and decrements them. This -// is done at each safepoint. -// -class CounterDecay : public AllStatic { - static jlong _last_timestamp; - public: - static void decay(); - static bool is_decay_needed() { return (os::javaTimeMillis() - _last_timestamp) > CounterDecayMinIntervalLength; } -}; + diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 4ff5aa0fa88..e35ecf2be61 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -455,11 +455,11 @@ address SharedRuntime::get_poll_stub(address pc) { if (at_poll_return) { assert(SharedRuntime::polling_page_return_handler_blob() != NULL, "polling page return stub not created yet"); - stub = SharedRuntime::polling_page_return_handler_blob()->instructions_begin(); + stub = SharedRuntime::polling_page_return_handler_blob()->entry_point(); } else { assert(SharedRuntime::polling_page_safepoint_handler_blob() != NULL, "polling page safepoint stub not created yet"); - stub = SharedRuntime::polling_page_safepoint_handler_blob()->instructions_begin(); + stub = SharedRuntime::polling_page_safepoint_handler_blob()->entry_point(); } #ifndef PRODUCT if( TraceSafepoint ) { @@ -574,7 +574,7 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, } // found handling method => lookup exception handler - int catch_pco = ret_pc - nm->instructions_begin(); + int catch_pco = ret_pc - nm->code_begin(); ExceptionHandlerTable table(nm); HandlerTableEntry *t = table.entry_for(catch_pco, handler_bci, scope_depth); @@ -607,7 +607,7 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, return NULL; } - return nm->instructions_begin() + t->pco(); + return nm->code_begin() + t->pco(); } JRT_ENTRY(void, SharedRuntime::throw_AbstractMethodError(JavaThread* thread)) @@ -1633,8 +1633,13 @@ char* SharedRuntime::generate_class_cast_message( char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread, oopDesc* required, oopDesc* actual) { + if (TraceMethodHandles) { + tty->print_cr("WrongMethodType thread="PTR_FORMAT" req="PTR_FORMAT" act="PTR_FORMAT"", + thread, required, actual); + } assert(EnableMethodHandles, ""); oop singleKlass = wrong_method_type_is_for_single_argument(thread, required); + char* message = NULL; if (singleKlass != NULL) { const char* objName = "argument or return value"; if (actual != NULL) { @@ -1647,7 +1652,7 @@ char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread, Klass* targetKlass = Klass::cast(required->is_klass() ? (klassOop)required : java_lang_Class::as_klassOop(required)); - return generate_class_cast_message(objName, targetKlass->external_name()); + message = generate_class_cast_message(objName, targetKlass->external_name()); } else { // %%% need to get the MethodType string, without messing around too much // Get a signature from the invoke instruction @@ -1679,9 +1684,13 @@ char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread, if (mhName[0] == '$') mhName = actual_method->signature()->as_C_string(); } - return generate_class_cast_message(mhName, targetType, - " cannot be called as "); + message = generate_class_cast_message(mhName, targetType, + " cannot be called as "); } + if (TraceMethodHandles) { + tty->print_cr("WrongMethodType => message=%s", message); + } + return message; } oop SharedRuntime::wrong_method_type_is_for_single_argument(JavaThread* thr, @@ -2252,7 +2261,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) { ResourceMark rm; - NOT_PRODUCT(int code_size); + NOT_PRODUCT(int insts_size); AdapterBlob* B = NULL; AdapterHandlerEntry* entry = NULL; AdapterFingerPrint* fingerprint = NULL; @@ -2305,7 +2314,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) { BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache if (buf != NULL) { - CodeBuffer buffer(buf->instructions_begin(), buf->instructions_size()); + CodeBuffer buffer(buf); short buffer_locs[20]; buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs, sizeof(buffer_locs)/sizeof(relocInfo)); @@ -2321,19 +2330,19 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) { #ifdef ASSERT if (VerifyAdapterSharing) { if (shared_entry != NULL) { - assert(shared_entry->compare_code(buf->instructions_begin(), buffer.code_size(), total_args_passed, sig_bt), + assert(shared_entry->compare_code(buf->code_begin(), buffer.insts_size(), total_args_passed, sig_bt), "code must match"); // Release the one just created and return the original _adapters->free_entry(entry); return shared_entry; } else { - entry->save_code(buf->instructions_begin(), buffer.code_size(), total_args_passed, sig_bt); + entry->save_code(buf->code_begin(), buffer.insts_size(), total_args_passed, sig_bt); } } #endif B = AdapterBlob::create(&buffer); - NOT_PRODUCT(code_size = buffer.code_size()); + NOT_PRODUCT(insts_size = buffer.insts_size()); } if (B == NULL) { // CodeCache is full, disable compilation @@ -2343,16 +2352,16 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) { CompileBroker::handle_full_code_cache(); return NULL; // Out of CodeCache space } - entry->relocate(B->instructions_begin()); + entry->relocate(B->content_begin()); #ifndef PRODUCT // debugging suppport if (PrintAdapterHandlers) { tty->cr(); tty->print_cr("i2c argument handler #%d for: %s %s (fingerprint = %s, %d bytes generated)", _adapters->number_of_entries(), (method->is_static() ? "static" : "receiver"), - method->signature()->as_C_string(), fingerprint->as_string(), code_size ); + method->signature()->as_C_string(), fingerprint->as_string(), insts_size ); tty->print_cr("c2i argument handler starts at %p",entry->get_c2i_entry()); - Disassembler::decode(entry->get_i2c_entry(), entry->get_i2c_entry() + code_size); + Disassembler::decode(entry->get_i2c_entry(), entry->get_i2c_entry() + insts_size); } #endif @@ -2366,13 +2375,11 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) { "%s(%s)@" PTR_FORMAT, B->name(), fingerprint->as_string(), - B->instructions_begin()); - Forte::register_stub(blob_id, B->instructions_begin(), B->instructions_end()); + B->content_begin()); + Forte::register_stub(blob_id, B->content_begin(), B->content_end()); if (JvmtiExport::should_post_dynamic_code_generated()) { - JvmtiExport::post_dynamic_code_generated(blob_id, - B->instructions_begin(), - B->instructions_end()); + JvmtiExport::post_dynamic_code_generated(blob_id, B->content_begin(), B->content_end()); } } return entry; @@ -2456,7 +2463,7 @@ nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method) { BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache if (buf != NULL) { - CodeBuffer buffer(buf->instructions_begin(), buf->instructions_size()); + CodeBuffer buffer(buf); double locs_buf[20]; buffer.insts()->initialize_shared_locs((relocInfo*)locs_buf, sizeof(locs_buf) / sizeof(relocInfo)); MacroAssembler _masm(&buffer); @@ -2493,15 +2500,13 @@ nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method) { } // Must unlock before calling set_code + // Install the generated code. if (nm != NULL) { method->set_code(method, nm); nm->post_compiled_method_load_event(); } else { // CodeCache is full, disable compilation - // Ought to log this but compile log is only per compile thread - // and we're some non descript Java thread. - MutexUnlocker mu(AdapterHandlerLibrary_lock); CompileBroker::handle_full_code_cache(); } return nm; @@ -2542,7 +2547,7 @@ nmethod *AdapterHandlerLibrary::create_dtrace_nmethod(methodHandle method) { BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache if (buf != NULL) { - CodeBuffer buffer(buf->instructions_begin(), buf->instructions_size()); + CodeBuffer buffer(buf); // Need a few relocation entries double locs_buf[20]; buffer.insts()->initialize_shared_locs( diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index bd5031e49a4..4f6d103f838 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -173,12 +173,12 @@ class SharedRuntime: AllStatic { static address get_ic_miss_stub() { assert(_ic_miss_blob!= NULL, "oops"); - return _ic_miss_blob->instructions_begin(); + return _ic_miss_blob->entry_point(); } static address get_handle_wrong_method_stub() { assert(_wrong_method_blob!= NULL, "oops"); - return _wrong_method_blob->instructions_begin(); + return _wrong_method_blob->entry_point(); } #ifdef COMPILER2 @@ -188,15 +188,15 @@ class SharedRuntime: AllStatic { static address get_resolve_opt_virtual_call_stub(){ assert(_resolve_opt_virtual_call_blob != NULL, "oops"); - return _resolve_opt_virtual_call_blob->instructions_begin(); + return _resolve_opt_virtual_call_blob->entry_point(); } static address get_resolve_virtual_call_stub() { assert(_resolve_virtual_call_blob != NULL, "oops"); - return _resolve_virtual_call_blob->instructions_begin(); + return _resolve_virtual_call_blob->entry_point(); } static address get_resolve_static_call_stub() { assert(_resolve_static_call_blob != NULL, "oops"); - return _resolve_static_call_blob->instructions_begin(); + return _resolve_static_call_blob->entry_point(); } static SafepointBlob* polling_page_return_handler_blob() { return _polling_page_return_handler_blob; } @@ -548,16 +548,17 @@ class SharedRuntime: AllStatic { // This library manages argument marshaling adapters and native wrappers. // There are 2 flavors of adapters: I2C and C2I. // -// The I2C flavor takes a stock interpreted call setup, marshals the arguments -// for a Java-compiled call, and jumps to Rmethod-> code()-> -// instructions_begin(). It is broken to call it without an nmethod assigned. -// The usual behavior is to lift any register arguments up out of the stack -// and possibly re-pack the extra arguments to be contigious. I2C adapters -// will save what the interpreter's stack pointer will be after arguments are -// popped, then adjust the interpreter's frame size to force alignment and -// possibly to repack the arguments. After re-packing, it jumps to the -// compiled code start. There are no safepoints in this adapter code and a GC -// cannot happen while marshaling is in progress. +// The I2C flavor takes a stock interpreted call setup, marshals the +// arguments for a Java-compiled call, and jumps to Rmethod-> code()-> +// code_begin(). It is broken to call it without an nmethod assigned. +// The usual behavior is to lift any register arguments up out of the +// stack and possibly re-pack the extra arguments to be contigious. +// I2C adapters will save what the interpreter's stack pointer will be +// after arguments are popped, then adjust the interpreter's frame +// size to force alignment and possibly to repack the arguments. +// After re-packing, it jumps to the compiled code start. There are +// no safepoints in this adapter code and a GC cannot happen while +// marshaling is in progress. // // The C2I flavor takes a stock compiled call setup plus the target method in // Rmethod, marshals the arguments for an interpreted call and jumps to diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp new file mode 100644 index 00000000000..ce8495675ad --- /dev/null +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +# include "incls/_precompiled.incl" +# include "incls/_simpleThresholdPolicy.cpp.incl" + +// Print an event. +void SimpleThresholdPolicy::print_event(EventType type, methodHandle mh, methodHandle imh, + int bci, CompLevel level) { + bool inlinee_event = mh() != imh(); + + ttyLocker tty_lock; + tty->print("%lf: [", os::elapsedTime()); + + int invocation_count = mh->invocation_count(); + int backedge_count = mh->backedge_count(); + switch(type) { + case CALL: + tty->print("call"); + break; + case LOOP: + tty->print("loop"); + break; + case COMPILE: + tty->print("compile"); + } + + tty->print(" level: %d ", level); + + ResourceMark rm; + char *method_name = mh->name_and_sig_as_C_string(); + tty->print("[%s", method_name); + // We can have an inlinee, although currently we don't generate any notifications for the inlined methods. + if (inlinee_event) { + char *inlinee_name = imh->name_and_sig_as_C_string(); + tty->print(" [%s]] ", inlinee_name); + } + else tty->print("] "); + tty->print("@%d queues: %d,%d", bci, CompileBroker::queue_size(CompLevel_full_profile), + CompileBroker::queue_size(CompLevel_full_optimization)); + + print_specific(type, mh, imh, bci, level); + + if (type != COMPILE) { + methodDataHandle mdh = mh->method_data(); + int mdo_invocations = 0, mdo_backedges = 0; + if (mdh() != NULL) { + mdo_invocations = mdh->invocation_count(); + mdo_backedges = mdh->backedge_count(); + } + tty->print(" total: %d,%d mdo: %d,%d", + invocation_count, backedge_count, + mdo_invocations, mdo_backedges); + tty->print(" max levels: %d,%d", + mh->highest_comp_level(), mh->highest_osr_comp_level()); + if (inlinee_event) { + tty->print(" inlinee max levels: %d,%d", imh->highest_comp_level(), imh->highest_osr_comp_level()); + } + tty->print(" compilable: "); + bool need_comma = false; + if (!mh->is_not_compilable(CompLevel_full_profile)) { + tty->print("c1"); + need_comma = true; + } + if (!mh->is_not_compilable(CompLevel_full_optimization)) { + if (need_comma) tty->print(", "); + tty->print("c2"); + need_comma = true; + } + if (!mh->is_not_osr_compilable()) { + if (need_comma) tty->print(", "); + tty->print("osr"); + } + tty->print(" status:"); + if (mh->queued_for_compilation()) { + tty->print(" in queue"); + } else tty->print(" idle"); + } + tty->print_cr("]"); +} + +void SimpleThresholdPolicy::initialize() { + if (FLAG_IS_DEFAULT(CICompilerCount)) { + FLAG_SET_DEFAULT(CICompilerCount, 3); + } + int count = CICompilerCount; + if (CICompilerCountPerCPU) { + count = MAX2(log2_intptr(os::active_processor_count()), 1) * 3 / 2; + } + set_c1_count(MAX2(count / 3, 1)); + set_c2_count(MAX2(count - count / 3, 1)); +} + +void SimpleThresholdPolicy::set_carry_if_necessary(InvocationCounter *counter) { + if (!counter->carry() && counter->count() > InvocationCounter::count_limit / 2) { + counter->set_carry_flag(); + } +} + +// Set carry flags on the counters if necessary +void SimpleThresholdPolicy::handle_counter_overflow(methodOop method) { + set_carry_if_necessary(method->invocation_counter()); + set_carry_if_necessary(method->backedge_counter()); + methodDataOop mdo = method->method_data(); + if (mdo != NULL) { + set_carry_if_necessary(mdo->invocation_counter()); + set_carry_if_necessary(mdo->backedge_counter()); + } +} + +// Called with the queue locked and with at least one element +CompileTask* SimpleThresholdPolicy::select_task(CompileQueue* compile_queue) { + return compile_queue->first(); +} + +nmethod* SimpleThresholdPolicy::event(methodHandle method, methodHandle inlinee, + int branch_bci, int bci, CompLevel comp_level, TRAPS) { + if (comp_level == CompLevel_none && + JvmtiExport::can_post_interpreter_events()) { + assert(THREAD->is_Java_thread(), "Should be java thread"); + if (((JavaThread*)THREAD)->is_interp_only_mode()) { + return NULL; + } + } + nmethod *osr_nm = NULL; + + handle_counter_overflow(method()); + if (method() != inlinee()) { + handle_counter_overflow(inlinee()); + } + + if (PrintTieredEvents) { + print_event(bci == InvocationEntryBci ? CALL : LOOP, method, inlinee, bci, comp_level); + } + + if (bci == InvocationEntryBci) { + method_invocation_event(method, inlinee, comp_level, THREAD); + } else { + method_back_branch_event(method, inlinee, bci, comp_level, THREAD); + int highest_level = method->highest_osr_comp_level(); + if (highest_level > comp_level) { + osr_nm = method->lookup_osr_nmethod_for(bci, highest_level, false); + } + } + return osr_nm; +} + +// Check if the method can be compiled, change level if necessary +void SimpleThresholdPolicy::compile(methodHandle mh, int bci, CompLevel level, TRAPS) { + // Take the given ceiling into the account. + // NOTE: You can set it to 1 to get a pure C1 version. + if ((CompLevel)TieredStopAtLevel < level) { + level = (CompLevel)TieredStopAtLevel; + } + if (level == CompLevel_none) { + return; + } + // Check if the method can be compiled, if not - try different levels. + if (!can_be_compiled(mh, level)) { + if (level < CompLevel_full_optimization && can_be_compiled(mh, CompLevel_full_optimization)) { + compile(mh, bci, CompLevel_full_optimization, THREAD); + } + if (level == CompLevel_full_optimization && can_be_compiled(mh, CompLevel_simple)) { + compile(mh, bci, CompLevel_simple, THREAD); + } + return; + } + if (bci != InvocationEntryBci && mh->is_not_osr_compilable()) { + return; + } + if (PrintTieredEvents) { + print_event(COMPILE, mh, mh, bci, level); + } + if (!CompileBroker::compilation_is_in_queue(mh, bci)) { + submit_compile(mh, bci, level, THREAD); + } +} + +// Tell the broker to compile the method +void SimpleThresholdPolicy::submit_compile(methodHandle mh, int bci, CompLevel level, TRAPS) { + int hot_count = (bci == InvocationEntryBci) ? mh->invocation_count() : mh->backedge_count(); + CompileBroker::compile_method(mh, bci, level, mh, hot_count, "tiered", THREAD); +} + +// Call and loop predicates determine whether a transition to a higher +// compilation level should be performed (pointers to predicate functions +// are passed to common() transition function). +bool SimpleThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level) { + switch(cur_level) { + case CompLevel_none: + case CompLevel_limited_profile: { + return loop_predicate_helper(i, b, 1.0); + } + case CompLevel_full_profile: { + return loop_predicate_helper(i, b, 1.0); + } + default: + return true; + } +} + +bool SimpleThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level) { + switch(cur_level) { + case CompLevel_none: + case CompLevel_limited_profile: { + return call_predicate_helper(i, b, 1.0); + } + case CompLevel_full_profile: { + return call_predicate_helper(i, b, 1.0); + } + default: + return true; + } +} + +// Determine is a method is mature. +bool SimpleThresholdPolicy::is_mature(methodOop method) { + if (is_trivial(method)) return true; + methodDataOop mdo = method->method_data(); + if (mdo != NULL) { + int i = mdo->invocation_count(); + int b = mdo->backedge_count(); + double k = ProfileMaturityPercentage / 100.0; + return call_predicate_helper(i, b, k) || + loop_predicate_helper(i, b, k); + } + return false; +} + +// Common transition function. Given a predicate determines if a method should transition to another level. +CompLevel SimpleThresholdPolicy::common(Predicate p, methodOop method, CompLevel cur_level) { + CompLevel next_level = cur_level; + int i = method->invocation_count(); + int b = method->backedge_count(); + + switch(cur_level) { + case CompLevel_none: + { + methodDataOop mdo = method->method_data(); + if (mdo != NULL) { + int mdo_i = mdo->invocation_count(); + int mdo_b = mdo->backedge_count(); + // If we were at full profile level, would we switch to full opt? + if ((this->*p)(mdo_i, mdo_b, CompLevel_full_profile)) { + next_level = CompLevel_full_optimization; + } + } + } + if (next_level == cur_level && (this->*p)(i, b, cur_level)) { + if (is_trivial(method)) { + next_level = CompLevel_simple; + } else { + next_level = CompLevel_full_profile; + } + } + break; + case CompLevel_limited_profile: + case CompLevel_full_profile: + if (is_trivial(method)) { + next_level = CompLevel_simple; + } else { + methodDataOop mdo = method->method_data(); + guarantee(mdo != NULL, "MDO should always exist"); + if (mdo->would_profile()) { + int mdo_i = mdo->invocation_count(); + int mdo_b = mdo->backedge_count(); + if ((this->*p)(mdo_i, mdo_b, cur_level)) { + next_level = CompLevel_full_optimization; + } + } else { + next_level = CompLevel_full_optimization; + } + } + break; + } + return next_level; +} + +// Determine if a method should be compiled with a normal entry point at a different level. +CompLevel SimpleThresholdPolicy::call_event(methodOop method, CompLevel cur_level) { + CompLevel highest_level = (CompLevel)method->highest_comp_level(); + if (cur_level == CompLevel_none && highest_level > cur_level) { + // TODO: We may want to try to do more extensive reprofiling in this case. + return highest_level; + } + + CompLevel osr_level = (CompLevel) method->highest_osr_comp_level(); + CompLevel next_level = common(&SimpleThresholdPolicy::call_predicate, method, cur_level); + + // If OSR method level is greater than the regular method level, the levels should be + // equalized by raising the regular method level in order to avoid OSRs during each + // invocation of the method. + if (osr_level == CompLevel_full_optimization && cur_level == CompLevel_full_profile) { + methodDataOop mdo = method->method_data(); + guarantee(mdo != NULL, "MDO should not be NULL"); + if (mdo->invocation_count() >= 1) { + next_level = CompLevel_full_optimization; + } + } else { + next_level = MAX2(osr_level, next_level); + } + + return next_level; +} + +// Determine if we should do an OSR compilation of a given method. +CompLevel SimpleThresholdPolicy::loop_event(methodOop method, CompLevel cur_level) { + if (cur_level == CompLevel_none) { + // If there is a live OSR method that means that we deopted to the interpreter + // for the transition. + CompLevel osr_level = (CompLevel)method->highest_osr_comp_level(); + if (osr_level > CompLevel_none) { + return osr_level; + } + } + return common(&SimpleThresholdPolicy::loop_predicate, method, cur_level); +} + + +// Handle the invocation event. +void SimpleThresholdPolicy::method_invocation_event(methodHandle mh, methodHandle imh, + CompLevel level, TRAPS) { + if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, InvocationEntryBci)) { + CompLevel next_level = call_event(mh(), level); + if (next_level != level) { + compile(mh, InvocationEntryBci, next_level, THREAD); + } + } +} + +// Handle the back branch event. Notice that we can compile the method +// with a regular entry from here. +void SimpleThresholdPolicy::method_back_branch_event(methodHandle mh, methodHandle imh, + int bci, CompLevel level, TRAPS) { + // If the method is already compiling, quickly bail out. + if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, bci)) { + // Use loop event as an opportinity to also check there's been + // enough calls. + CompLevel cur_level = comp_level(mh()); + CompLevel next_level = call_event(mh(), cur_level); + CompLevel next_osr_level = loop_event(mh(), level); + + next_level = MAX2(next_level, + next_osr_level < CompLevel_full_optimization ? next_osr_level : cur_level); + bool is_compiling = false; + if (next_level != cur_level) { + compile(mh, InvocationEntryBci, next_level, THREAD); + is_compiling = true; + } + + // Do the OSR version + if (!is_compiling && next_osr_level != level) { + compile(mh, bci, next_osr_level, THREAD); + } + } +} diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp new file mode 100644 index 00000000000..293b190320a --- /dev/null +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class CompileTask; +class CompileQueue; + +class SimpleThresholdPolicy : public CompilationPolicy { + int _c1_count, _c2_count; + + // Check if the counter is big enough and set carry (effectively infinity). + inline void set_carry_if_necessary(InvocationCounter *counter); + // Set carry flags in the counters (in methodOop and MDO). + inline void handle_counter_overflow(methodOop method); + // Call and loop predicates determine whether a transition to a higher compilation + // level should be performed (pointers to predicate functions are passed to common_TF(). + // Predicates also take compiler load into account. + typedef bool (SimpleThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level); + bool call_predicate(int i, int b, CompLevel cur_level); + bool loop_predicate(int i, int b, CompLevel cur_level); + // Common transition function. Given a predicate determines if a method should transition to another level. + CompLevel common(Predicate p, methodOop method, CompLevel cur_level); + // Transition functions. + // call_event determines if a method should be compiled at a different + // level with a regular invocation entry. + CompLevel call_event(methodOop method, CompLevel cur_level); + // loop_event checks if a method should be OSR compiled at a different + // level. + CompLevel loop_event(methodOop method, CompLevel cur_level); + +protected: + int c1_count() const { return _c1_count; } + int c2_count() const { return _c2_count; } + void set_c1_count(int x) { _c1_count = x; } + void set_c2_count(int x) { _c2_count = x; } + + enum EventType { CALL, LOOP, COMPILE }; + void print_event(EventType type, methodHandle mh, methodHandle imh, int bci, CompLevel level); + // Print policy-specific information if necessary + virtual void print_specific(EventType type, methodHandle mh, methodHandle imh, int bci, CompLevel level) { } + // Check if the method can be compiled, change level if necessary + void compile(methodHandle mh, int bci, CompLevel level, TRAPS); + // Submit a given method for compilation + virtual void submit_compile(methodHandle mh, int bci, CompLevel level, TRAPS); + // Simple methods are as good being compiled with C1 as C2. + // This function tells if it's such a function. + inline bool is_trivial(methodOop method); + + // Predicate helpers are used by .*_predicate() methods as well as others. + // They check the given counter values, multiplied by the scale against the thresholds. + template static inline bool call_predicate_helper(int i, int b, double scale); + template static inline bool loop_predicate_helper(int i, int b, double scale); + + // Get a compilation level for a given method. + static CompLevel comp_level(methodOop method) { + nmethod *nm = method->code(); + if (nm != NULL && nm->is_in_use()) { + return (CompLevel)nm->comp_level(); + } + return CompLevel_none; + } + virtual void method_invocation_event(methodHandle method, methodHandle inlinee, + CompLevel level, TRAPS); + virtual void method_back_branch_event(methodHandle method, methodHandle inlinee, + int bci, CompLevel level, TRAPS); +public: + SimpleThresholdPolicy() : _c1_count(0), _c2_count(0) { } + virtual int compiler_count(CompLevel comp_level) { + if (is_c1_compile(comp_level)) return c1_count(); + if (is_c2_compile(comp_level)) return c2_count(); + return 0; + } + virtual void do_safepoint_work() { } + virtual void delay_compilation(methodOop method) { } + virtual void disable_compilation(methodOop method) { } + // TODO: we should honour reprofiling requests in the future. Currently reprofiling + // would happen but not to the extent we would ideally like. + virtual void reprofile(ScopeDesc* trap_scope, bool is_osr) { } + virtual nmethod* event(methodHandle method, methodHandle inlinee, + int branch_bci, int bci, CompLevel comp_level, TRAPS); + // Select task is called by CompileBroker. We should return a task or NULL. + virtual CompileTask* select_task(CompileQueue* compile_queue); + // Tell the runtime if we think a given method is adequately profiled. + virtual bool is_mature(methodOop method); + // Initialize: set compiler thread count + virtual void initialize(); +}; diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp new file mode 100644 index 00000000000..00d16d502f6 --- /dev/null +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + +template +bool SimpleThresholdPolicy::call_predicate_helper(int i, int b, double scale) { + switch(level) { + case CompLevel_none: + case CompLevel_limited_profile: + return (i > Tier3InvocationThreshold * scale) || + (i > Tier3MinInvocationThreshold * scale && i + b > Tier3CompileThreshold * scale); + case CompLevel_full_profile: + return (i > Tier4InvocationThreshold * scale) || + (i > Tier4MinInvocationThreshold * scale && i + b > Tier4CompileThreshold * scale); + } + return true; +} + +template +bool SimpleThresholdPolicy::loop_predicate_helper(int i, int b, double scale) { + switch(level) { + case CompLevel_none: + case CompLevel_limited_profile: + return b > Tier3BackEdgeThreshold * scale; + case CompLevel_full_profile: + return b > Tier4BackEdgeThreshold * scale; + } + return true; +} + +// Simple methods are as good being compiled with C1 as C2. +// Determine if a given method is such a case. +bool SimpleThresholdPolicy::is_trivial(methodOop method) { + if (method->is_accessor()) return true; + if (method->code() != NULL) { + methodDataOop mdo = method->method_data(); + if (mdo != NULL && mdo->num_loops() == 0 && + (method->code_size() < 5 || (mdo->num_blocks() < 4) && (method->code_size() < 15))) { + return !mdo->would_profile(); + } + } + return false; +} diff --git a/hotspot/src/share/vm/runtime/stubRoutines.cpp b/hotspot/src/share/vm/runtime/stubRoutines.cpp index 0b39eb700ca..d87c8bfae04 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp @@ -97,6 +97,15 @@ address StubRoutines::_checkcast_arraycopy = NULL; address StubRoutines::_unsafe_arraycopy = NULL; address StubRoutines::_generic_arraycopy = NULL; + +address StubRoutines::_jbyte_fill; +address StubRoutines::_jshort_fill; +address StubRoutines::_jint_fill; +address StubRoutines::_arrayof_jbyte_fill; +address StubRoutines::_arrayof_jshort_fill; +address StubRoutines::_arrayof_jint_fill; + + double (* StubRoutines::_intrinsic_log )(double) = NULL; double (* StubRoutines::_intrinsic_log10 )(double) = NULL; double (* StubRoutines::_intrinsic_exp )(double) = NULL; @@ -119,10 +128,9 @@ void StubRoutines::initialize1() { TraceTime timer("StubRoutines generation 1", TraceStartupTime); _code1 = BufferBlob::create("StubRoutines (1)", code_size1); if (_code1 == NULL) { - vm_exit_out_of_memory(code_size1, - "CodeCache: no room for StubRoutines (1)"); + vm_exit_out_of_memory(code_size1, "CodeCache: no room for StubRoutines (1)"); } - CodeBuffer buffer(_code1->instructions_begin(), _code1->instructions_size()); + CodeBuffer buffer(_code1); StubGenerator_generate(&buffer, false); } } @@ -172,10 +180,9 @@ void StubRoutines::initialize2() { TraceTime timer("StubRoutines generation 2", TraceStartupTime); _code2 = BufferBlob::create("StubRoutines (2)", code_size2); if (_code2 == NULL) { - vm_exit_out_of_memory(code_size2, - "CodeCache: no room for StubRoutines (2)"); + vm_exit_out_of_memory(code_size2, "CodeCache: no room for StubRoutines (2)"); } - CodeBuffer buffer(_code2->instructions_begin(), _code2->instructions_size()); + CodeBuffer buffer(_code2); StubGenerator_generate(&buffer, true); } @@ -195,6 +202,46 @@ void StubRoutines::initialize2() { #undef TEST_ARRAYCOPY +#define TEST_FILL(type) \ + if (_##type##_fill != NULL) { \ + union { \ + double d; \ + type body[96]; \ + } s; \ + \ + int v = 32; \ + for (int offset = -2; offset <= 2; offset++) { \ + for (int i = 0; i < 96; i++) { \ + s.body[i] = 1; \ + } \ + type* start = s.body + 8 + offset; \ + for (int aligned = 0; aligned < 2; aligned++) { \ + if (aligned) { \ + if (((intptr_t)start) % HeapWordSize == 0) { \ + ((void (*)(type*, int, int))StubRoutines::_arrayof_##type##_fill)(start, v, 80); \ + } else { \ + continue; \ + } \ + } else { \ + ((void (*)(type*, int, int))StubRoutines::_##type##_fill)(start, v, 80); \ + } \ + for (int i = 0; i < 96; i++) { \ + if (i < (8 + offset) || i >= (88 + offset)) { \ + assert(s.body[i] == 1, "what?"); \ + } else { \ + assert(s.body[i] == 32, "what?"); \ + } \ + } \ + } \ + } \ + } \ + + TEST_FILL(jbyte); + TEST_FILL(jshort); + TEST_FILL(jint); + +#undef TEST_FILL + #define TEST_COPYRTN(type) \ test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::conjoint_##type##s_atomic), sizeof(type)); \ test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::arrayof_conjoint_##type##s), (int)MAX2(sizeof(HeapWord), sizeof(type))) @@ -315,3 +362,39 @@ JRT_LEAF(void, StubRoutines::arrayof_oop_copy(HeapWord* src, HeapWord* dest, siz Copy::arrayof_conjoint_oops(src, dest, count); gen_arraycopy_barrier((oop *) dest, count); JRT_END + + +address StubRoutines::select_fill_function(BasicType t, bool aligned, const char* &name) { +#define RETURN_STUB(xxx_fill) { \ + name = #xxx_fill; \ + return StubRoutines::xxx_fill(); } + + switch (t) { + case T_BYTE: + case T_BOOLEAN: + if (!aligned) RETURN_STUB(jbyte_fill); + RETURN_STUB(arrayof_jbyte_fill); + case T_CHAR: + case T_SHORT: + if (!aligned) RETURN_STUB(jshort_fill); + RETURN_STUB(arrayof_jshort_fill); + case T_INT: + case T_FLOAT: + if (!aligned) RETURN_STUB(jint_fill); + RETURN_STUB(arrayof_jint_fill); + case T_DOUBLE: + case T_LONG: + case T_ARRAY: + case T_OBJECT: + case T_NARROWOOP: + case T_ADDRESS: + // Currently unsupported + return NULL; + + default: + ShouldNotReachHere(); + return NULL; + } + +#undef RETURN_STUB +} diff --git a/hotspot/src/share/vm/runtime/stubRoutines.hpp b/hotspot/src/share/vm/runtime/stubRoutines.hpp index f09d5ae1b8f..6b51e316bd8 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.hpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp @@ -148,6 +148,13 @@ class StubRoutines: AllStatic { static address _unsafe_arraycopy; static address _generic_arraycopy; + static address _jbyte_fill; + static address _jshort_fill; + static address _jint_fill; + static address _arrayof_jbyte_fill; + static address _arrayof_jshort_fill; + static address _arrayof_jint_fill; + // These are versions of the java.lang.Math methods which perform // the same operations as the intrinsic version. They are used for // constant folding in the compiler to ensure equivalence. If the @@ -259,6 +266,16 @@ class StubRoutines: AllStatic { static address unsafe_arraycopy() { return _unsafe_arraycopy; } static address generic_arraycopy() { return _generic_arraycopy; } + static address jbyte_fill() { return _jbyte_fill; } + static address jshort_fill() { return _jshort_fill; } + static address jint_fill() { return _jint_fill; } + static address arrayof_jbyte_fill() { return _arrayof_jbyte_fill; } + static address arrayof_jshort_fill() { return _arrayof_jshort_fill; } + static address arrayof_jint_fill() { return _arrayof_jint_fill; } + + static address select_fill_function(BasicType t, bool aligned, const char* &name); + + static double intrinsic_log(double d) { assert(_intrinsic_log != NULL, "must be defined"); return _intrinsic_log(d); diff --git a/hotspot/src/share/vm/runtime/sweeper.cpp b/hotspot/src/share/vm/runtime/sweeper.cpp index a252440df36..d4171992f0a 100644 --- a/hotspot/src/share/vm/runtime/sweeper.cpp +++ b/hotspot/src/share/vm/runtime/sweeper.cpp @@ -368,8 +368,7 @@ void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) { disconnected++; } else if (nm->is_speculatively_disconnected()) { // This method was previously considered for preemptive unloading and was not called since then - nm->method()->invocation_counter()->decay(); - nm->method()->backedge_counter()->decay(); + CompilationPolicy::policy()->delay_compilation(nm->method()); nm->make_not_entrant(); made_not_entrant++; } diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 35afb6fe6b5..00e5e991efc 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -2110,8 +2110,7 @@ void JavaThread::check_safepoint_and_suspend_for_native_trans(JavaThread *thread } if (f.id() == thread->must_deopt_id()) { thread->clear_must_deopt_id(); - // Since we know we're safe to deopt the current state is a safe state - f.deoptimize(thread, true); + f.deoptimize(thread); } else { fatal("missed deoptimization!"); } diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 78f676e9c48..4857811aed7 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -604,7 +604,8 @@ static inline uint64_t cast_uint64_t(size_t x) nonstatic_field(CodeBlob, _size, int) \ nonstatic_field(CodeBlob, _header_size, int) \ nonstatic_field(CodeBlob, _relocation_size, int) \ - nonstatic_field(CodeBlob, _instructions_offset, int) \ + nonstatic_field(CodeBlob, _content_offset, int) \ + nonstatic_field(CodeBlob, _code_offset, int) \ nonstatic_field(CodeBlob, _frame_complete_offset, int) \ nonstatic_field(CodeBlob, _data_offset, int) \ nonstatic_field(CodeBlob, _frame_size, int) \ diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index 30dada5e07a..f72b5df354a 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.cpp @@ -121,7 +121,8 @@ const char* Abstract_VM_Version::vm_vendor() { #ifdef VENDOR return XSTR(VENDOR); #else - return "Sun Microsystems Inc."; + return JDK_Version::is_gte_jdk17x_version() ? + "Oracle Corporation" : "Sun Microsystems Inc."; #endif } diff --git a/hotspot/src/share/vm/services/g1MemoryPool.cpp b/hotspot/src/share/vm/services/g1MemoryPool.cpp index 03a88738d43..140a1ece01d 100644 --- a/hotspot/src/share/vm/services/g1MemoryPool.cpp +++ b/hotspot/src/share/vm/services/g1MemoryPool.cpp @@ -28,12 +28,11 @@ G1MemoryPoolSuper::G1MemoryPoolSuper(G1CollectedHeap* g1h, const char* name, size_t init_size, - size_t max_size, bool support_usage_threshold) : _g1h(g1h), CollectedMemoryPool(name, MemoryPool::Heap, init_size, - max_size, + undefined_max(), support_usage_threshold) { assert(UseG1GC, "sanity"); } @@ -52,13 +51,6 @@ size_t G1MemoryPoolSuper::eden_space_used(G1CollectedHeap* g1h) { return eden_used; } -// See the comment at the top of g1MemoryPool.hpp -size_t G1MemoryPoolSuper::eden_space_max(G1CollectedHeap* g1h) { - // This should ensure that it returns a value no smaller than the - // region size. Currently, eden_space_committed() guarantees that. - return eden_space_committed(g1h); -} - // See the comment at the top of g1MemoryPool.hpp size_t G1MemoryPoolSuper::survivor_space_committed(G1CollectedHeap* g1h) { return MAX2(survivor_space_used(g1h), (size_t) HeapRegion::GrainBytes); @@ -71,13 +63,6 @@ size_t G1MemoryPoolSuper::survivor_space_used(G1CollectedHeap* g1h) { return survivor_used; } -// See the comment at the top of g1MemoryPool.hpp -size_t G1MemoryPoolSuper::survivor_space_max(G1CollectedHeap* g1h) { - // This should ensure that it returns a value no smaller than the - // region size. Currently, survivor_space_committed() guarantees that. - return survivor_space_committed(g1h); -} - // See the comment at the top of g1MemoryPool.hpp size_t G1MemoryPoolSuper::old_space_committed(G1CollectedHeap* g1h) { size_t committed = overall_committed(g1h); @@ -99,24 +84,11 @@ size_t G1MemoryPoolSuper::old_space_used(G1CollectedHeap* g1h) { return used; } -// See the comment at the top of g1MemoryPool.hpp -size_t G1MemoryPoolSuper::old_space_max(G1CollectedHeap* g1h) { - size_t max = overall_max(g1h); - size_t eden_max = eden_space_max(g1h); - size_t survivor_max = survivor_space_max(g1h); - max = subtract_up_to_zero(max, eden_max); - max = subtract_up_to_zero(max, survivor_max); - max = MAX2(max, (size_t) HeapRegion::GrainBytes); - return max; -} - G1EdenPool::G1EdenPool(G1CollectedHeap* g1h) : G1MemoryPoolSuper(g1h, "G1 Eden", eden_space_committed(g1h), /* init_size */ - eden_space_max(g1h), /* max_size */ - false /* support_usage_threshold */) { -} + false /* support_usage_threshold */) { } MemoryUsage G1EdenPool::get_memory_usage() { size_t initial_sz = initial_size(); @@ -131,9 +103,7 @@ G1SurvivorPool::G1SurvivorPool(G1CollectedHeap* g1h) : G1MemoryPoolSuper(g1h, "G1 Survivor", survivor_space_committed(g1h), /* init_size */ - survivor_space_max(g1h), /* max_size */ - false /* support_usage_threshold */) { -} + false /* support_usage_threshold */) { } MemoryUsage G1SurvivorPool::get_memory_usage() { size_t initial_sz = initial_size(); @@ -148,9 +118,7 @@ G1OldGenPool::G1OldGenPool(G1CollectedHeap* g1h) : G1MemoryPoolSuper(g1h, "G1 Old Gen", old_space_committed(g1h), /* init_size */ - old_space_max(g1h), /* max_size */ - true /* support_usage_threshold */) { -} + true /* support_usage_threshold */) { } MemoryUsage G1OldGenPool::get_memory_usage() { size_t initial_sz = initial_size(); diff --git a/hotspot/src/share/vm/services/g1MemoryPool.hpp b/hotspot/src/share/vm/services/g1MemoryPool.hpp index 5538e5660c6..a49377e959d 100644 --- a/hotspot/src/share/vm/services/g1MemoryPool.hpp +++ b/hotspot/src/share/vm/services/g1MemoryPool.hpp @@ -74,14 +74,20 @@ class G1CollectedHeap; // in the future. // // 3) Another decision that is again not straightforward is what is -// the max size that each memory pool can grow to. Right now, we set -// that the committed size for the eden and the survivors and -// calculate the old gen max as follows (basically, it's a similar -// pattern to what we use for the committed space, as described -// above): +// the max size that each memory pool can grow to. One way to do this +// would be to use the committed size for the max for the eden and +// survivors and calculate the old gen max as follows (basically, it's +// a similar pattern to what we use for the committed space, as +// described above): // // old_gen_max = overall_max - eden_max - survivor_max // +// Unfortunately, the above makes the max of each pool fluctuate over +// time and, even though this is allowed according to the spec, it +// broke several assumptions in the M&M framework (there were cases +// where used would reach a value greater than max). So, for max we +// use -1, which means "undefined" according to the spec. +// // 4) Now, there is a very subtle issue with all the above. The // framework will call get_memory_usage() on the three pools // asynchronously. As a result, each call might get a different value @@ -125,33 +131,30 @@ protected: G1MemoryPoolSuper(G1CollectedHeap* g1h, const char* name, size_t init_size, - size_t max_size, bool support_usage_threshold); // The reason why all the code is in static methods is so that it // can be safely called from the constructors of the subclasses. + static size_t undefined_max() { + return (size_t) -1; + } + static size_t overall_committed(G1CollectedHeap* g1h) { return g1h->capacity(); } static size_t overall_used(G1CollectedHeap* g1h) { return g1h->used_unlocked(); } - static size_t overall_max(G1CollectedHeap* g1h) { - return g1h->g1_reserved_obj_bytes(); - } static size_t eden_space_committed(G1CollectedHeap* g1h); static size_t eden_space_used(G1CollectedHeap* g1h); - static size_t eden_space_max(G1CollectedHeap* g1h); static size_t survivor_space_committed(G1CollectedHeap* g1h); static size_t survivor_space_used(G1CollectedHeap* g1h); - static size_t survivor_space_max(G1CollectedHeap* g1h); static size_t old_space_committed(G1CollectedHeap* g1h); static size_t old_space_used(G1CollectedHeap* g1h); - static size_t old_space_max(G1CollectedHeap* g1h); }; // Memory pool that represents the G1 eden. @@ -163,7 +166,7 @@ public: return eden_space_used(_g1h); } size_t max_size() const { - return eden_space_max(_g1h); + return undefined_max(); } MemoryUsage get_memory_usage(); }; @@ -177,7 +180,7 @@ public: return survivor_space_used(_g1h); } size_t max_size() const { - return survivor_space_max(_g1h); + return undefined_max(); } MemoryUsage get_memory_usage(); }; @@ -191,7 +194,7 @@ public: return old_space_used(_g1h); } size_t max_size() const { - return old_space_max(_g1h); + return undefined_max(); } MemoryUsage get_memory_usage(); }; diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp index 40dc2d04148..d7685ca0b15 100644 --- a/hotspot/src/share/vm/services/heapDumper.cpp +++ b/hotspot/src/share/vm/services/heapDumper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1305,6 +1305,8 @@ class VM_HeapDumper : public VM_GC_Operation { static VM_HeapDumper* _global_dumper; static DumpWriter* _global_writer; DumpWriter* _local_writer; + JavaThread* _oome_thread; + methodOop _oome_constructor; bool _gc_before_heap_dump; bool _is_segmented_dump; jlong _dump_start; @@ -1366,7 +1368,7 @@ class VM_HeapDumper : public VM_GC_Operation { void end_of_dump(); public: - VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump) : + VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome) : VM_GC_Operation(0 /* total collections, dummy, ignored */, 0 /* total full collections, dummy, ignored */, gc_before_heap_dump) { @@ -1377,6 +1379,18 @@ class VM_HeapDumper : public VM_GC_Operation { _klass_map = new (ResourceObj::C_HEAP) GrowableArray(INITIAL_CLASS_COUNT, true); _stack_traces = NULL; _num_threads = 0; + if (oome) { + assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread"); + // get OutOfMemoryError zero-parameter constructor + instanceKlass* oome_ik = instanceKlass::cast(SystemDictionary::OutOfMemoryError_klass()); + _oome_constructor = oome_ik->find_method(vmSymbols::object_initializer_name(), + vmSymbols::void_method_signature()); + // get thread throwing OOME when generating the heap dump at OOME + _oome_thread = JavaThread::current(); + } else { + _oome_thread = NULL; + _oome_constructor = NULL; + } } ~VM_HeapDumper() { if (_stack_traces != NULL) { @@ -1557,7 +1571,11 @@ int VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) { frame f = java_thread->last_frame(); vframe* vf = vframe::new_vframe(&f, ®_map, java_thread); frame* last_entry_frame = NULL; + int extra_frames = 0; + if (java_thread == _oome_thread && _oome_constructor != NULL) { + extra_frames++; + } while (vf != NULL) { blk.set_frame_number(stack_depth); if (vf->is_java_frame()) { @@ -1574,7 +1592,7 @@ int VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) { writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME); writer()->write_objectID(o); writer()->write_u4(thread_serial_num); - writer()->write_u4((u4) stack_depth); + writer()->write_u4((u4) (stack_depth + extra_frames)); } } } @@ -1764,6 +1782,17 @@ void VM_HeapDumper::dump_stack_traces() { // write HPROF_FRAME records for this thread's stack trace int depth = stack_trace->get_stack_depth(); int thread_frame_start = frame_serial_num; + int extra_frames = 0; + // write fake frame that makes it look like the thread, which caused OOME, + // is in the OutOfMemoryError zero-parameter constructor + if (thread == _oome_thread && _oome_constructor != NULL) { + int oome_serial_num = _klass_map->find(Klass::cast(_oome_constructor->method_holder())); + // the class serial number starts from 1 + assert(oome_serial_num > 0, "OutOfMemoryError class not found"); + DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, oome_serial_num, + _oome_constructor, 0); + extra_frames++; + } for (int j=0; j < depth; j++) { StackFrameInfo* frame = stack_trace->stack_frame_at(j); methodOop m = frame->method(); @@ -1772,6 +1801,7 @@ void VM_HeapDumper::dump_stack_traces() { assert(class_serial_num > 0, "class not found"); DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, class_serial_num, m, frame->bci()); } + depth += extra_frames; // write HPROF_TRACE record for one thread DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4) + depth*oopSize); @@ -1808,7 +1838,7 @@ int HeapDumper::dump(const char* path) { } // generate the dump - VM_HeapDumper dumper(&writer, _gc_before_heap_dump); + VM_HeapDumper dumper(&writer, _gc_before_heap_dump, _oome); if (Thread::current()->is_VM_thread()) { assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint"); dumper.doit(); @@ -1869,12 +1899,22 @@ void HeapDumper::set_error(char* error) { } } +// Called by out-of-memory error reporting by a single Java thread +// outside of a JVM safepoint +void HeapDumper::dump_heap_from_oome() { + HeapDumper::dump_heap(true); +} + // Called by error reporting by a single Java thread outside of a JVM safepoint, // or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various // callers are strictly serialized and guaranteed not to interfere below. For more // general use, however, this method will need modification to prevent // inteference when updating the static variables base_path and dump_file_seq below. void HeapDumper::dump_heap() { + HeapDumper::dump_heap(false); +} + +void HeapDumper::dump_heap(bool oome) { static char base_path[JVM_MAXPATHLEN] = {'\0'}; static uint dump_file_seq = 0; char my_path[JVM_MAXPATHLEN] = {'\0'}; @@ -1930,6 +1970,7 @@ void HeapDumper::dump_heap() { dump_file_seq++; // increment seq number for next time we dump HeapDumper dumper(false /* no GC before heap dump */, - true /* send to tty */); + true /* send to tty */, + oome /* pass along out-of-memory-error flag */); dumper.dump(my_path); } diff --git a/hotspot/src/share/vm/services/heapDumper.hpp b/hotspot/src/share/vm/services/heapDumper.hpp index 57ae9cf84d5..9dd4fd32950 100644 --- a/hotspot/src/share/vm/services/heapDumper.hpp +++ b/hotspot/src/share/vm/services/heapDumper.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,12 @@ class HeapDumper : public StackObj { char* _error; bool _print_to_tty; bool _gc_before_heap_dump; + bool _oome; elapsedTimer _t; + HeapDumper(bool gc_before_heap_dump, bool print_to_tty, bool oome) : + _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(print_to_tty), _oome(oome) { } + // string representation of error char* error() const { return _error; } void set_error(char* error); @@ -51,11 +55,11 @@ class HeapDumper : public StackObj { // internal timer. elapsedTimer* timer() { return &_t; } + static void dump_heap(bool oome); + public: HeapDumper(bool gc_before_heap_dump) : - _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(false) { } - HeapDumper(bool gc_before_heap_dump, bool print_to_tty) : - _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(print_to_tty) { } + _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(false), _oome(false) { } ~HeapDumper(); @@ -66,4 +70,6 @@ class HeapDumper : public StackObj { char* error_as_C_string() const; static void dump_heap() KERNEL_RETURN; + + static void dump_heap_from_oome() KERNEL_RETURN; }; diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index dd6c3bc9b0e..9df9107d457 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -785,10 +785,11 @@ JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap)) } } - // In our current implementation, all pools should have - // defined init and max size - assert(!has_undefined_init_size, "Undefined init size"); - assert(!has_undefined_max_size, "Undefined max size"); + // In our current implementation, we make sure that all non-heap + // pools have defined init and max sizes. Heap pools do not matter, + // as we never use total_init and total_max for them. + assert(heap || !has_undefined_init_size, "Undefined init size"); + assert(heap || !has_undefined_max_size, "Undefined max size"); MemoryUsage usage((heap ? InitialHeapSize : total_init), total_used, @@ -1900,16 +1901,15 @@ JVM_ENTRY(void, jmm_GetLastGCStat(JNIEnv *env, jobject obj, jmmGCStat *gc_stat)) // Get the GCMemoryManager GCMemoryManager* mgr = get_gc_memory_manager_from_jobject(obj, CHECK); - if (mgr->last_gc_stat() == NULL) { - gc_stat->gc_index = 0; - return; - } // Make a copy of the last GC statistics // GC may occur while constructing the last GC information int num_pools = MemoryService::num_memory_pools(); GCStatInfo* stat = new GCStatInfo(num_pools); - stat->copy_stat(mgr->last_gc_stat()); + if (mgr->get_last_gc_stat(stat) == 0) { + gc_stat->gc_index = 0; + return; + } gc_stat->gc_index = stat->gc_index(); gc_stat->start_time = Management::ticks_to_ms(stat->start_time()); diff --git a/hotspot/src/share/vm/services/memoryManager.cpp b/hotspot/src/share/vm/services/memoryManager.cpp index 0266b331dcd..4921ae1f569 100644 --- a/hotspot/src/share/vm/services/memoryManager.cpp +++ b/hotspot/src/share/vm/services/memoryManager.cpp @@ -166,17 +166,6 @@ GCStatInfo::~GCStatInfo() { FREE_C_HEAP_ARRAY(MemoryUsage*, _after_gc_usage_array); } -void GCStatInfo::copy_stat(GCStatInfo* stat) { - set_index(stat->gc_index()); - set_start_time(stat->start_time()); - set_end_time(stat->end_time()); - assert(_usage_array_size == stat->usage_array_size(), "Must have same array size"); - for (int i = 0; i < _usage_array_size; i++) { - set_before_gc_usage(i, stat->before_gc_usage_for_pool(i)); - set_after_gc_usage(i, stat->after_gc_usage_for_pool(i)); - } -} - void GCStatInfo::set_gc_usage(int pool_index, MemoryUsage usage, bool before_gc) { MemoryUsage* gc_usage_array; if (before_gc) { @@ -187,67 +176,129 @@ void GCStatInfo::set_gc_usage(int pool_index, MemoryUsage usage, bool before_gc) gc_usage_array[pool_index] = usage; } +void GCStatInfo::clear() { + _index = 0; + _start_time = 0L; + _end_time = 0L; + size_t len = _usage_array_size * sizeof(MemoryUsage); + memset(_before_gc_usage_array, 0, len); + memset(_after_gc_usage_array, 0, len); +} + + GCMemoryManager::GCMemoryManager() : MemoryManager() { _num_collections = 0; _last_gc_stat = NULL; + _last_gc_lock = new Mutex(Mutex::leaf, "_last_gc_lock", true); + _current_gc_stat = NULL; _num_gc_threads = 1; } GCMemoryManager::~GCMemoryManager() { delete _last_gc_stat; + delete _last_gc_lock; + delete _current_gc_stat; } void GCMemoryManager::initialize_gc_stat_info() { assert(MemoryService::num_memory_pools() > 0, "should have one or more memory pools"); _last_gc_stat = new GCStatInfo(MemoryService::num_memory_pools()); + _current_gc_stat = new GCStatInfo(MemoryService::num_memory_pools()); + // tracking concurrent collections we need two objects: one to update, and one to + // hold the publicly available "last (completed) gc" information. } -void GCMemoryManager::gc_begin() { - assert(_last_gc_stat != NULL, "Just checking"); - _accumulated_timer.start(); - _num_collections++; - _last_gc_stat->set_index(_num_collections); - _last_gc_stat->set_start_time(Management::timestamp()); +void GCMemoryManager::gc_begin(bool recordGCBeginTime, bool recordPreGCUsage, + bool recordAccumulatedGCTime) { + assert(_last_gc_stat != NULL && _current_gc_stat != NULL, "Just checking"); + if (recordAccumulatedGCTime) { + _accumulated_timer.start(); + } + // _num_collections now increases in gc_end, to count completed collections + if (recordGCBeginTime) { + _current_gc_stat->set_index(_num_collections+1); + _current_gc_stat->set_start_time(Management::timestamp()); + } - // Keep memory usage of all memory pools - for (int i = 0; i < MemoryService::num_memory_pools(); i++) { - MemoryPool* pool = MemoryService::get_memory_pool(i); - MemoryUsage usage = pool->get_memory_usage(); - _last_gc_stat->set_before_gc_usage(i, usage); - HS_DTRACE_PROBE8(hotspot, mem__pool__gc__begin, - name(), strlen(name()), - pool->name(), strlen(pool->name()), - usage.init_size(), usage.used(), - usage.committed(), usage.max_size()); + if (recordPreGCUsage) { + // Keep memory usage of all memory pools + for (int i = 0; i < MemoryService::num_memory_pools(); i++) { + MemoryPool* pool = MemoryService::get_memory_pool(i); + MemoryUsage usage = pool->get_memory_usage(); + _current_gc_stat->set_before_gc_usage(i, usage); + HS_DTRACE_PROBE8(hotspot, mem__pool__gc__begin, + name(), strlen(name()), + pool->name(), strlen(pool->name()), + usage.init_size(), usage.used(), + usage.committed(), usage.max_size()); + } } } -void GCMemoryManager::gc_end() { - _accumulated_timer.stop(); - _last_gc_stat->set_end_time(Management::timestamp()); - - int i; - // keep the last gc statistics for all memory pools - for (i = 0; i < MemoryService::num_memory_pools(); i++) { - MemoryPool* pool = MemoryService::get_memory_pool(i); - MemoryUsage usage = pool->get_memory_usage(); - - HS_DTRACE_PROBE8(hotspot, mem__pool__gc__end, - name(), strlen(name()), - pool->name(), strlen(pool->name()), - usage.init_size(), usage.used(), - usage.committed(), usage.max_size()); - - _last_gc_stat->set_after_gc_usage(i, usage); +// A collector MUST, even if it does not complete for some reason, +// make a TraceMemoryManagerStats object where countCollection is true, +// to ensure the current gc stat is placed in _last_gc_stat. +void GCMemoryManager::gc_end(bool recordPostGCUsage, + bool recordAccumulatedGCTime, + bool recordGCEndTime, bool countCollection) { + if (recordAccumulatedGCTime) { + _accumulated_timer.stop(); + } + if (recordGCEndTime) { + _current_gc_stat->set_end_time(Management::timestamp()); } - // Set last collection usage of the memory pools managed by this collector - for (i = 0; i < num_memory_pools(); i++) { - MemoryPool* pool = get_memory_pool(i); - MemoryUsage usage = pool->get_memory_usage(); + if (recordPostGCUsage) { + int i; + // keep the last gc statistics for all memory pools + for (i = 0; i < MemoryService::num_memory_pools(); i++) { + MemoryPool* pool = MemoryService::get_memory_pool(i); + MemoryUsage usage = pool->get_memory_usage(); - // Compare with GC usage threshold - pool->set_last_collection_usage(usage); - LowMemoryDetector::detect_after_gc_memory(pool); + HS_DTRACE_PROBE8(hotspot, mem__pool__gc__end, + name(), strlen(name()), + pool->name(), strlen(pool->name()), + usage.init_size(), usage.used(), + usage.committed(), usage.max_size()); + + _current_gc_stat->set_after_gc_usage(i, usage); + } + + // Set last collection usage of the memory pools managed by this collector + for (i = 0; i < num_memory_pools(); i++) { + MemoryPool* pool = get_memory_pool(i); + MemoryUsage usage = pool->get_memory_usage(); + + // Compare with GC usage threshold + pool->set_last_collection_usage(usage); + LowMemoryDetector::detect_after_gc_memory(pool); + } + } + if (countCollection) { + _num_collections++; + // alternately update two objects making one public when complete + { + MutexLockerEx ml(_last_gc_lock, Mutex::_no_safepoint_check_flag); + GCStatInfo *tmp = _last_gc_stat; + _last_gc_stat = _current_gc_stat; + _current_gc_stat = tmp; + // reset the current stat for diagnosability purposes + _current_gc_stat->clear(); + } } } + +size_t GCMemoryManager::get_last_gc_stat(GCStatInfo* dest) { + MutexLockerEx ml(_last_gc_lock, Mutex::_no_safepoint_check_flag); + if (_last_gc_stat->gc_index() != 0) { + dest->set_index(_last_gc_stat->gc_index()); + dest->set_start_time(_last_gc_stat->start_time()); + dest->set_end_time(_last_gc_stat->end_time()); + assert(dest->usage_array_size() == _last_gc_stat->usage_array_size(), + "Must have same array size"); + size_t len = dest->usage_array_size() * sizeof(MemoryUsage); + memcpy(dest->before_gc_usage_array(), _last_gc_stat->before_gc_usage_array(), len); + memcpy(dest->after_gc_usage_array(), _last_gc_stat->after_gc_usage_array(), len); + } + return _last_gc_stat->gc_index(); +} diff --git a/hotspot/src/share/vm/services/memoryManager.hpp b/hotspot/src/share/vm/services/memoryManager.hpp index 70b7eef717b..7399141a83a 100644 --- a/hotspot/src/share/vm/services/memoryManager.hpp +++ b/hotspot/src/share/vm/services/memoryManager.hpp @@ -131,6 +131,9 @@ public: return _after_gc_usage_array[pool_index]; } + MemoryUsage* before_gc_usage_array() { return _before_gc_usage_array; } + MemoryUsage* after_gc_usage_array() { return _after_gc_usage_array; } + void set_index(size_t index) { _index = index; } void set_start_time(jlong time) { _start_time = time; } void set_end_time(jlong time) { _end_time = time; } @@ -143,7 +146,7 @@ public: set_gc_usage(pool_index, usage, false /* after gc */); } - void copy_stat(GCStatInfo* stat); + void clear(); }; class GCMemoryManager : public MemoryManager { @@ -153,6 +156,8 @@ private: elapsedTimer _accumulated_timer; elapsedTimer _gc_timer; // for measuring every GC duration GCStatInfo* _last_gc_stat; + Mutex* _last_gc_lock; + GCStatInfo* _current_gc_stat; int _num_gc_threads; public: GCMemoryManager(); @@ -166,11 +171,16 @@ public: int num_gc_threads() { return _num_gc_threads; } void set_num_gc_threads(int count) { _num_gc_threads = count; } - void gc_begin(); - void gc_end(); + void gc_begin(bool recordGCBeginTime, bool recordPreGCUsage, + bool recordAccumulatedGCTime); + void gc_end(bool recordPostGCUsage, bool recordAccumulatedGCTime, + bool recordGCEndTime, bool countCollection); void reset_gc_stat() { _num_collections = 0; _accumulated_timer.reset(); } - GCStatInfo* last_gc_stat() { return _last_gc_stat; } + + // Copy out _last_gc_stat to the given destination, returning + // the collection count. Zero signifies no gc has taken place. + size_t get_last_gc_stat(GCStatInfo* dest); virtual MemoryManager::Name kind() = 0; }; diff --git a/hotspot/src/share/vm/services/memoryService.cpp b/hotspot/src/share/vm/services/memoryService.cpp index 3c55fffadae..c50a4fefe68 100644 --- a/hotspot/src/share/vm/services/memoryService.cpp +++ b/hotspot/src/share/vm/services/memoryService.cpp @@ -509,7 +509,10 @@ void MemoryService::track_memory_pool_usage(MemoryPool* pool) { } } -void MemoryService::gc_begin(bool fullGC) { +void MemoryService::gc_begin(bool fullGC, bool recordGCBeginTime, + bool recordAccumulatedGCTime, + bool recordPreGCUsage, bool recordPeakUsage) { + GCMemoryManager* mgr; if (fullGC) { mgr = _major_gc_manager; @@ -517,16 +520,21 @@ void MemoryService::gc_begin(bool fullGC) { mgr = _minor_gc_manager; } assert(mgr->is_gc_memory_manager(), "Sanity check"); - mgr->gc_begin(); + mgr->gc_begin(recordGCBeginTime, recordPreGCUsage, recordAccumulatedGCTime); // Track the peak memory usage when GC begins - for (int i = 0; i < _pools_list->length(); i++) { - MemoryPool* pool = _pools_list->at(i); - pool->record_peak_memory_usage(); + if (recordPeakUsage) { + for (int i = 0; i < _pools_list->length(); i++) { + MemoryPool* pool = _pools_list->at(i); + pool->record_peak_memory_usage(); + } } } -void MemoryService::gc_end(bool fullGC) { +void MemoryService::gc_end(bool fullGC, bool recordPostGCUsage, + bool recordAccumulatedGCTime, + bool recordGCEndTime, bool countCollection) { + GCMemoryManager* mgr; if (fullGC) { mgr = (GCMemoryManager*) _major_gc_manager; @@ -536,7 +544,8 @@ void MemoryService::gc_end(bool fullGC) { assert(mgr->is_gc_memory_manager(), "Sanity check"); // register the GC end statistics and memory usage - mgr->gc_end(); + mgr->gc_end(recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime, + countCollection); } void MemoryService::oops_do(OopClosure* f) { @@ -585,12 +594,12 @@ Handle MemoryService::create_MemoryUsage_obj(MemoryUsage usage, TRAPS) { return obj; } // -// GC manager type depends on the type of Generation. Depending the space -// availablity and vm option the gc uses major gc manager or minor gc +// GC manager type depends on the type of Generation. Depending on the space +// availablity and vm options the gc uses major gc manager or minor gc // manager or both. The type of gc manager depends on the generation kind. -// For DefNew, ParNew and ASParNew generation doing scavange gc uses minor -// gc manager (so _fullGC is set to false ) and for other generation kind -// DOing mark-sweep-compact uses major gc manager (so _fullGC is set +// For DefNew, ParNew and ASParNew generation doing scavenge gc uses minor +// gc manager (so _fullGC is set to false ) and for other generation kinds +// doing mark-sweep-compact uses major gc manager (so _fullGC is set // to true). TraceMemoryManagerStats::TraceMemoryManagerStats(Generation::Name kind) { switch (kind) { @@ -611,13 +620,48 @@ TraceMemoryManagerStats::TraceMemoryManagerStats(Generation::Name kind) { default: assert(false, "Unrecognized gc generation kind."); } - MemoryService::gc_begin(_fullGC); + // this has to be called in a stop the world pause and represent + // an entire gc pause, start to finish: + initialize(_fullGC, true, true, true, true, true, true, true); } -TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC) { +TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC, + bool recordGCBeginTime, + bool recordPreGCUsage, + bool recordPeakUsage, + bool recordPostGCUsage, + bool recordAccumulatedGCTime, + bool recordGCEndTime, + bool countCollection) { + initialize(fullGC, recordGCBeginTime, recordPreGCUsage, recordPeakUsage, + recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime, + countCollection); +} + +// for a subclass to create then initialize an instance before invoking +// the MemoryService +void TraceMemoryManagerStats::initialize(bool fullGC, + bool recordGCBeginTime, + bool recordPreGCUsage, + bool recordPeakUsage, + bool recordPostGCUsage, + bool recordAccumulatedGCTime, + bool recordGCEndTime, + bool countCollection) { _fullGC = fullGC; - MemoryService::gc_begin(_fullGC); + _recordGCBeginTime = recordGCBeginTime; + _recordPreGCUsage = recordPreGCUsage; + _recordPeakUsage = recordPeakUsage; + _recordPostGCUsage = recordPostGCUsage; + _recordAccumulatedGCTime = recordAccumulatedGCTime; + _recordGCEndTime = recordGCEndTime; + _countCollection = countCollection; + + MemoryService::gc_begin(_fullGC, _recordGCBeginTime, _recordAccumulatedGCTime, + _recordPreGCUsage, _recordPeakUsage); } TraceMemoryManagerStats::~TraceMemoryManagerStats() { - MemoryService::gc_end(_fullGC); + MemoryService::gc_end(_fullGC, _recordPostGCUsage, _recordAccumulatedGCTime, + _recordGCEndTime, _countCollection); } + diff --git a/hotspot/src/share/vm/services/memoryService.hpp b/hotspot/src/share/vm/services/memoryService.hpp index a21f3d1dc7f..cf26f1987bb 100644 --- a/hotspot/src/share/vm/services/memoryService.hpp +++ b/hotspot/src/share/vm/services/memoryService.hpp @@ -149,8 +149,13 @@ public: } static void track_memory_pool_usage(MemoryPool* pool); - static void gc_begin(bool fullGC); - static void gc_end(bool fullGC); + static void gc_begin(bool fullGC, bool recordGCBeginTime, + bool recordAccumulatedGCTime, + bool recordPreGCUsage, bool recordPeakUsage); + static void gc_end(bool fullGC, bool recordPostGCUsage, + bool recordAccumulatedGCTime, + bool recordGCEndTime, bool countCollection); + static void oops_do(OopClosure* f); @@ -164,8 +169,34 @@ public: class TraceMemoryManagerStats : public StackObj { private: bool _fullGC; + bool _recordGCBeginTime; + bool _recordPreGCUsage; + bool _recordPeakUsage; + bool _recordPostGCUsage; + bool _recordAccumulatedGCTime; + bool _recordGCEndTime; + bool _countCollection; + public: - TraceMemoryManagerStats(bool fullGC); + TraceMemoryManagerStats() {} + TraceMemoryManagerStats(bool fullGC, + bool recordGCBeginTime = true, + bool recordPreGCUsage = true, + bool recordPeakUsage = true, + bool recordPostGCUsage = true, + bool recordAccumulatedGCTime = true, + bool recordGCEndTime = true, + bool countCollection = true); + + void initialize(bool fullGC, + bool recordGCBeginTime, + bool recordPreGCUsage, + bool recordPeakUsage, + bool recordPostGCUsage, + bool recordAccumulatedGCTime, + bool recordGCEndTime, + bool countCollection); + TraceMemoryManagerStats(Generation::Name kind); ~TraceMemoryManagerStats(); }; diff --git a/hotspot/src/share/vm/utilities/accessFlags.hpp b/hotspot/src/share/vm/utilities/accessFlags.hpp index a2b57dab1b7..e10ac5fe955 100644 --- a/hotspot/src/share/vm/utilities/accessFlags.hpp +++ b/hotspot/src/share/vm/utilities/accessFlags.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,8 @@ enum { JVM_ACC_HAS_LOOPS = 0x40000000, // Method has loops JVM_ACC_LOOPS_FLAG_INIT = (int)0x80000000,// The loop flag has been initialized JVM_ACC_QUEUED = 0x01000000, // Queued for compilation - JVM_ACC_NOT_TIER1_COMPILABLE = 0x04000000, + JVM_ACC_NOT_C2_COMPILABLE = 0x02000000, + JVM_ACC_NOT_C1_COMPILABLE = 0x04000000, JVM_ACC_NOT_OSR_COMPILABLE = 0x08000000, JVM_ACC_HAS_LINE_NUMBER_TABLE = 0x00100000, JVM_ACC_HAS_CHECKED_EXCEPTIONS = 0x00400000, @@ -47,6 +48,7 @@ enum { JVM_ACC_IS_OLD = 0x00010000, // RedefineClasses() has replaced this method JVM_ACC_IS_OBSOLETE = 0x00020000, // RedefineClasses() has made method obsolete JVM_ACC_IS_PREFIXED_NATIVE = 0x00040000, // JVMTI has prefixed this native method + JVM_MH_INVOKE_BITS // = 0x10001100 // MethodHandle.invoke quasi-native = (JVM_ACC_NATIVE | JVM_ACC_SYNTHETIC | JVM_ACC_MONITOR_MATCH), @@ -108,7 +110,8 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC { bool has_loops () const { return (_flags & JVM_ACC_HAS_LOOPS ) != 0; } bool loops_flag_init () const { return (_flags & JVM_ACC_LOOPS_FLAG_INIT ) != 0; } bool queued_for_compilation () const { return (_flags & JVM_ACC_QUEUED ) != 0; } - bool is_not_tier1_compilable () const { return (_flags & JVM_ACC_NOT_TIER1_COMPILABLE ) != 0; } + bool is_not_c1_compilable () const { return (_flags & JVM_ACC_NOT_C1_COMPILABLE ) != 0; } + bool is_not_c2_compilable () const { return (_flags & JVM_ACC_NOT_C2_COMPILABLE ) != 0; } bool is_not_osr_compilable () const { return (_flags & JVM_ACC_NOT_OSR_COMPILABLE ) != 0; } bool has_linenumber_table () const { return (_flags & JVM_ACC_HAS_LINE_NUMBER_TABLE ) != 0; } bool has_checked_exceptions () const { return (_flags & JVM_ACC_HAS_CHECKED_EXCEPTIONS ) != 0; } @@ -172,7 +175,8 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC { void set_has_monitor_bytecodes() { atomic_set_bits(JVM_ACC_HAS_MONITOR_BYTECODES); } void set_has_loops() { atomic_set_bits(JVM_ACC_HAS_LOOPS); } void set_loops_flag_init() { atomic_set_bits(JVM_ACC_LOOPS_FLAG_INIT); } - void set_not_tier1_compilable() { atomic_set_bits(JVM_ACC_NOT_TIER1_COMPILABLE); } + void set_not_c1_compilable() { atomic_set_bits(JVM_ACC_NOT_C1_COMPILABLE); } + void set_not_c2_compilable() { atomic_set_bits(JVM_ACC_NOT_C2_COMPILABLE); } void set_not_osr_compilable() { atomic_set_bits(JVM_ACC_NOT_OSR_COMPILABLE); } void set_has_linenumber_table() { atomic_set_bits(JVM_ACC_HAS_LINE_NUMBER_TABLE); } void set_has_checked_exceptions() { atomic_set_bits(JVM_ACC_HAS_CHECKED_EXCEPTIONS); } diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index 7b1cd2200b0..54282bf0740 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -234,7 +234,7 @@ void report_java_out_of_memory(const char* message) { // create heap dump before OnOutOfMemoryError commands are executed if (HeapDumpOnOutOfMemoryError) { tty->print_cr("java.lang.OutOfMemoryError: %s", message); - HeapDumper::dump_heap(); + HeapDumper::dump_heap_from_oome(); } if (OnOutOfMemoryError && OnOutOfMemoryError[0]) { diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 97d96c21f12..d9c32be8a27 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -529,7 +529,7 @@ extern int _type2aelembytes[T_CONFLICT+1]; // maps a BasicType to nof bytes used #ifdef ASSERT extern int type2aelembytes(BasicType t, bool allow_address = false); // asserts #else -inline int type2aelembytes(BasicType t) { return _type2aelembytes[t]; } +inline int type2aelembytes(BasicType t, bool allow_address = false) { return _type2aelembytes[t]; } #endif @@ -710,24 +710,41 @@ enum MethodCompilation { // Enumeration to distinguish tiers of compilation enum CompLevel { - CompLevel_none = 0, - CompLevel_fast_compile = 1, - CompLevel_full_optimization = 2, + CompLevel_any = -1, + CompLevel_all = -1, + CompLevel_none = 0, // Interpreter + CompLevel_simple = 1, // C1 + CompLevel_limited_profile = 2, // C1, invocation & backedge counters + CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo + CompLevel_full_optimization = 4, // C2 - CompLevel_highest_tier = CompLevel_full_optimization, -#ifdef TIERED - CompLevel_initial_compile = CompLevel_fast_compile +#if defined(COMPILER2) + CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered +#elif defined(COMPILER1) + CompLevel_highest_tier = CompLevel_simple, // pure C1 #else - CompLevel_initial_compile = CompLevel_full_optimization -#endif // TIERED + CompLevel_highest_tier = CompLevel_none, +#endif + +#if defined(TIERED) + CompLevel_initial_compile = CompLevel_full_profile // tiered +#elif defined(COMPILER1) + CompLevel_initial_compile = CompLevel_simple // pure C1 +#elif defined(COMPILER2) + CompLevel_initial_compile = CompLevel_full_optimization // pure C2 +#else + CompLevel_initial_compile = CompLevel_none +#endif }; -inline bool is_tier1_compile(int comp_level) { - return comp_level == CompLevel_fast_compile; +inline bool is_c1_compile(int comp_level) { + return comp_level > CompLevel_none && comp_level < CompLevel_full_optimization; } -inline bool is_tier2_compile(int comp_level) { + +inline bool is_c2_compile(int comp_level) { return comp_level == CompLevel_full_optimization; } + inline bool is_highest_tier_compile(int comp_level) { return comp_level == CompLevel_highest_tier; } @@ -1017,22 +1034,22 @@ inline intx byte_size(void* from, void* to) { // This routine takes eight bytes: inline u8 build_u8_from( u1 c1, u1 c2, u1 c3, u1 c4, u1 c5, u1 c6, u1 c7, u1 c8 ) { - return ( u8(c1) << 56 ) & ( u8(0xff) << 56 ) - | ( u8(c2) << 48 ) & ( u8(0xff) << 48 ) - | ( u8(c3) << 40 ) & ( u8(0xff) << 40 ) - | ( u8(c4) << 32 ) & ( u8(0xff) << 32 ) - | ( u8(c5) << 24 ) & ( u8(0xff) << 24 ) - | ( u8(c6) << 16 ) & ( u8(0xff) << 16 ) - | ( u8(c7) << 8 ) & ( u8(0xff) << 8 ) - | ( u8(c8) << 0 ) & ( u8(0xff) << 0 ); + return (( u8(c1) << 56 ) & ( u8(0xff) << 56 )) + | (( u8(c2) << 48 ) & ( u8(0xff) << 48 )) + | (( u8(c3) << 40 ) & ( u8(0xff) << 40 )) + | (( u8(c4) << 32 ) & ( u8(0xff) << 32 )) + | (( u8(c5) << 24 ) & ( u8(0xff) << 24 )) + | (( u8(c6) << 16 ) & ( u8(0xff) << 16 )) + | (( u8(c7) << 8 ) & ( u8(0xff) << 8 )) + | (( u8(c8) << 0 ) & ( u8(0xff) << 0 )); } // This routine takes four bytes: inline u4 build_u4_from( u1 c1, u1 c2, u1 c3, u1 c4 ) { - return ( u4(c1) << 24 ) & 0xff000000 - | ( u4(c2) << 16 ) & 0x00ff0000 - | ( u4(c3) << 8 ) & 0x0000ff00 - | ( u4(c4) << 0 ) & 0x000000ff; + return (( u4(c1) << 24 ) & 0xff000000) + | (( u4(c2) << 16 ) & 0x00ff0000) + | (( u4(c3) << 8 ) & 0x0000ff00) + | (( u4(c4) << 0 ) & 0x000000ff); } // And this one works if the four bytes are contiguous in memory: @@ -1042,8 +1059,8 @@ inline u4 build_u4_from( u1* p ) { // Ditto for two-byte ints: inline u2 build_u2_from( u1 c1, u1 c2 ) { - return u2(( u2(c1) << 8 ) & 0xff00 - | ( u2(c2) << 0 ) & 0x00ff); + return u2((( u2(c1) << 8 ) & 0xff00) + | (( u2(c2) << 0 ) & 0x00ff)); } // And this one works if the two bytes are contiguous in memory: @@ -1066,14 +1083,14 @@ inline jfloat build_float_from( u1* p ) { // now (64-bit) longs inline jlong build_long_from( u1 c1, u1 c2, u1 c3, u1 c4, u1 c5, u1 c6, u1 c7, u1 c8 ) { - return ( jlong(c1) << 56 ) & ( jlong(0xff) << 56 ) - | ( jlong(c2) << 48 ) & ( jlong(0xff) << 48 ) - | ( jlong(c3) << 40 ) & ( jlong(0xff) << 40 ) - | ( jlong(c4) << 32 ) & ( jlong(0xff) << 32 ) - | ( jlong(c5) << 24 ) & ( jlong(0xff) << 24 ) - | ( jlong(c6) << 16 ) & ( jlong(0xff) << 16 ) - | ( jlong(c7) << 8 ) & ( jlong(0xff) << 8 ) - | ( jlong(c8) << 0 ) & ( jlong(0xff) << 0 ); + return (( jlong(c1) << 56 ) & ( jlong(0xff) << 56 )) + | (( jlong(c2) << 48 ) & ( jlong(0xff) << 48 )) + | (( jlong(c3) << 40 ) & ( jlong(0xff) << 40 )) + | (( jlong(c4) << 32 ) & ( jlong(0xff) << 32 )) + | (( jlong(c5) << 24 ) & ( jlong(0xff) << 24 )) + | (( jlong(c6) << 16 ) & ( jlong(0xff) << 16 )) + | (( jlong(c7) << 8 ) & ( jlong(0xff) << 8 )) + | (( jlong(c8) << 0 ) & ( jlong(0xff) << 0 )); } inline jlong build_long_from( u1* p ) { diff --git a/hotspot/src/share/vm/utilities/macros.hpp b/hotspot/src/share/vm/utilities/macros.hpp index 4f89f2aebe0..39528c9e669 100644 --- a/hotspot/src/share/vm/utilities/macros.hpp +++ b/hotspot/src/share/vm/utilities/macros.hpp @@ -71,17 +71,27 @@ #define NOT_COMPILER2(code) code #endif // COMPILER2 +#ifdef TIERED +#define TIERED_ONLY(code) code +#define NOT_TIERED(code) +#else +#define TIERED_ONLY(code) +#define NOT_TIERED(code) code +#endif // TIERED + // PRODUCT variant #ifdef PRODUCT #define PRODUCT_ONLY(code) code #define NOT_PRODUCT(code) +#define NOT_PRODUCT_ARG(arg) #define PRODUCT_RETURN {} #define PRODUCT_RETURN0 { return 0; } #define PRODUCT_RETURN_(code) { code } #else // PRODUCT #define PRODUCT_ONLY(code) #define NOT_PRODUCT(code) code +#define NOT_PRODUCT_ARG(arg) arg, #define PRODUCT_RETURN /*next token must be ;*/ #define PRODUCT_RETURN0 /*next token must be ;*/ #define PRODUCT_RETURN_(code) /*next token must be ;*/ diff --git a/hotspot/src/share/vm/utilities/taskqueue.cpp b/hotspot/src/share/vm/utilities/taskqueue.cpp index 7a001803d96..2492b90d1d8 100644 --- a/hotspot/src/share/vm/utilities/taskqueue.cpp +++ b/hotspot/src/share/vm/utilities/taskqueue.cpp @@ -36,6 +36,14 @@ const char * const TaskQueueStats::_names[last_stat_id] = { "qpush", "qpop", "qpop-s", "qattempt", "qsteal", "opush", "omax" }; +TaskQueueStats & TaskQueueStats::operator +=(const TaskQueueStats & addend) +{ + for (unsigned int i = 0; i < last_stat_id; ++i) { + _stats[i] += addend._stats[i]; + } + return *this; +} + void TaskQueueStats::print_header(unsigned int line, outputStream* const stream, unsigned int width) { @@ -71,6 +79,29 @@ void TaskQueueStats::print(outputStream* stream, unsigned int width) const } #undef FMT } + +#ifdef ASSERT +// Invariants which should hold after a TaskQueue has been emptied and is +// quiescent; they do not hold at arbitrary times. +void TaskQueueStats::verify() const +{ + assert(get(push) == get(pop) + get(steal), + err_msg("push=" SIZE_FORMAT " pop=" SIZE_FORMAT " steal=" SIZE_FORMAT, + get(push), get(pop), get(steal))); + assert(get(pop_slow) <= get(pop), + err_msg("pop_slow=" SIZE_FORMAT " pop=" SIZE_FORMAT, + get(pop_slow), get(pop))); + assert(get(steal) <= get(steal_attempt), + err_msg("steal=" SIZE_FORMAT " steal_attempt=" SIZE_FORMAT, + get(steal), get(steal_attempt))); + assert(get(overflow) == 0 || get(push) != 0, + err_msg("overflow=" SIZE_FORMAT " push=" SIZE_FORMAT, + get(overflow), get(push))); + assert(get(overflow_max_len) == 0 || get(overflow) != 0, + err_msg("overflow_max_len=" SIZE_FORMAT " overflow=" SIZE_FORMAT, + get(overflow_max_len), get(overflow))); +} +#endif // ASSERT #endif // TASKQUEUE_STATS int TaskQueueSetSuper::randomParkAndMiller(int *seed0) { diff --git a/hotspot/src/share/vm/utilities/taskqueue.hpp b/hotspot/src/share/vm/utilities/taskqueue.hpp index 52e89fc8027..1bd1ae72309 100644 --- a/hotspot/src/share/vm/utilities/taskqueue.hpp +++ b/hotspot/src/share/vm/utilities/taskqueue.hpp @@ -59,15 +59,21 @@ public: inline void record_steal(bool success); inline void record_overflow(size_t new_length); + TaskQueueStats & operator +=(const TaskQueueStats & addend); + inline size_t get(StatId id) const { return _stats[id]; } inline const size_t* get() const { return _stats; } inline void reset(); + // Print the specified line of the header (does not include a line separator). static void print_header(unsigned int line, outputStream* const stream = tty, unsigned int width = 10); + // Print the statistics (does not include a line separator). void print(outputStream* const stream = tty, unsigned int width = 10) const; + DEBUG_ONLY(void verify() const;) + private: size_t _stats[last_stat_id]; static const char * const _names[last_stat_id]; diff --git a/hotspot/test/compiler/6894807/IsInstanceTest.java b/hotspot/test/compiler/6894807/IsInstanceTest.java new file mode 100644 index 00000000000..ddc3fed365a --- /dev/null +++ b/hotspot/test/compiler/6894807/IsInstanceTest.java @@ -0,0 +1,44 @@ +/* + * @test + * @bug 6894807 + * @summary No ClassCastException for HashAttributeSet constructors if run with -Xcomp + * @compile IsInstanceTest.java + * @run shell Test6894807.sh +*/ + +public class IsInstanceTest { + + public static void main(String[] args) { + BaseInterface baseInterfaceImpl = new BaseInterfaceImpl(); + for (int i = 0; i < 100000; i++) { + if (isInstanceOf(baseInterfaceImpl, ExtendedInterface.class)) { + System.out.println("Failed at index:" + i); + System.out.println("Arch: "+System.getProperty("os.arch", "")+ + " OS: "+System.getProperty("os.name", "")+ + " OSV: "+System.getProperty("os.version", "")+ + " Cores: "+Runtime.getRuntime().availableProcessors()+ + " JVM: "+System.getProperty("java.version", "")+" "+System.getProperty("sun.arch.data.model", "")); + break; + } + } + System.out.println("Done!"); + } + + public static boolean isInstanceOf(BaseInterface baseInterfaceImpl, Class... baseInterfaceClasses) { + for (Class baseInterfaceClass : baseInterfaceClasses) { + if (baseInterfaceClass.isInstance(baseInterfaceImpl)) { + return true; + } + } + return false; + } + + private interface BaseInterface { + } + + private interface ExtendedInterface extends BaseInterface { + } + + private static class BaseInterfaceImpl implements BaseInterface { + } +} diff --git a/hotspot/test/compiler/6894807/Test6894807.sh b/hotspot/test/compiler/6894807/Test6894807.sh new file mode 100644 index 00000000000..da435cc380f --- /dev/null +++ b/hotspot/test/compiler/6894807/Test6894807.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +if [ "${TESTSRC}" = "" ] +then TESTSRC=. +fi + +if [ "${TESTJAVA}" = "" ] +then + PARENT=`dirname \`which java\`` + TESTJAVA=`dirname ${PARENT}` + echo "TESTJAVA not set, selecting " ${TESTJAVA} + echo "If this is incorrect, try setting the variable manually." +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +BIT_FLAG="" + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + SunOS | Linux ) + NULL=/dev/null + PS=":" + FS="/" + ## for solaris, linux it's HOME + FILE_LOCATION=$HOME + if [ -f ${FILE_LOCATION}${FS}JDK64BIT -a ${OS} = "SunOS" ] + then + BIT_FLAG=`cat ${FILE_LOCATION}${FS}JDK64BIT | grep -v '^#'` + fi + ;; + Windows_* ) + NULL=NUL + PS=";" + FS="\\" + ;; + * ) + echo "Unrecognized system!" + exit 1; + ;; +esac + +JEMMYPATH=${CPAPPEND} +CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH + +THIS_DIR=`pwd` + +${TESTJAVA}${FS}bin${FS}java ${BIT_FLAG} -version + +${TESTJAVA}${FS}bin${FS}java ${BIT_FLAG} -server IsInstanceTest > test.out 2>&1 + +cat test.out + +grep "Failed at index" test.out + +if [ $? = 0 ] +then + echo "Test Failed" + exit 1 +else + echo "Test Passed" + exit 0 +fi diff --git a/hotspot/test/compiler/6982370/Test6982370.java b/hotspot/test/compiler/6982370/Test6982370.java new file mode 100644 index 00000000000..a3264abb274 --- /dev/null +++ b/hotspot/test/compiler/6982370/Test6982370.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 6982370 + * @summary SIGBUS in jbyte_fill + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+OptimizeFill -Xbatch Test6982370 + */ + +import java.util.Arrays; + +/** + * Exercise the fill routine for various short alignments and sizes + */ + +public class Test6982370 { + public static void main(String[] args) { + test_byte(); + test_char(); + test_short(); + test_int(); + test_float(); + } + + public static void test_int() { + int[] a = new int[16]; + for (int i = 0; i < 200000; i++) { + int start = i & 7; + int end = start + ((i >> 4) & 7); + int value = i; + if ((i & 1) == 1) value = -value; + Arrays.fill(a, start, end, value); + boolean error = false; + for (int j = start; j < end; j++) { + if (a[j] != value) { + System.err.println("a[" + j + "] = " + a[j] + " != " + value + " for " + a.length); + error = true; + } + } + if (error) throw new InternalError(); + } + } + + public static void test_float() { + float[] a = new float[16]; + for (int i = 0; i < 200000; i++) { + int start = i & 7; + int end = start + ((i >> 4) & 7); + float value = (float)i; + if ((i & 1) == 1) value = -value; + Arrays.fill(a, start, end, value); + boolean error = false; + for (int j = start; j < end; j++) { + if (a[j] != value) { + System.err.println("a[" + j + "] = " + a[j] + " != " + value + " for " + a.length); + error = true; + } + } + if (error) throw new InternalError(); + } + } + public static void test_char() { + char[] a = new char[16]; + for (int i = 0; i < 200000; i++) { + int start = i & 7; + int end = start + ((i >> 4) & 7); + char value = (char)i; + Arrays.fill(a, start, end, value); + boolean error = false; + for (int j = start; j < end; j++) { + if (a[j] != value) { + System.err.println("a[" + j + "] = " + a[j] + " != " + value + " for " + a.length); + error = true; + } + } + if (error) throw new InternalError(); + } + } + public static void test_short() { + short[] a = new short[16]; + for (int i = 0; i < 200000; i++) { + int start = i & 7; + int end = start + ((i >> 4) & 7); + short value = (short)i; + if ((i & 1) == 1) value = (short)-value; + Arrays.fill(a, start, end, value); + boolean error = false; + for (int j = start; j < end; j++) { + if (a[j] != value) { + System.err.println("a[" + j + "] = " + a[j] + " != " + value + " for " + a.length); + error = true; + } + } + if (error) throw new InternalError(); + } + } + + public static void test_byte() { + for (int i = 0; i < 200000; i++) { + byte[] a = new byte[16]; + int start = i & 7; + int end = start + ((i >> 4) & 7); + byte value = (byte)i; + if ((i & 1) == 1) value = (byte)-value; + Arrays.fill(a, start, end, value); + boolean error = false; + for (int j = start; j < end; j++) { + if (a[j] != value) { + System.err.println("a[" + j + "] = " + a[j] + " != " + value + " for " + a.length); + error = true; + } + } + if (error) throw new InternalError(); + } + } +} diff --git a/hotspot/test/gc/6581734/Test6581734.java b/hotspot/test/gc/6581734/Test6581734.java new file mode 100644 index 00000000000..143340dc080 --- /dev/null +++ b/hotspot/test/gc/6581734/Test6581734.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test Test6581734.java + * @bug 6581734 + * @summary CMS Old Gen's collection usage is zero after GC which is incorrect + * @run main/othervm -Xmx512m -verbose:gc -XX:+UseConcMarkSweepGC Test6581734 + * + */ +import java.util.*; +import java.lang.management.*; + +// 6581734 states that memory pool usage via the mbean is wrong +// for CMS (zero, even after a collection). +// +// 6580448 states that the collection count similarly is wrong +// (stays at zero for CMS collections) +// -- closed as dup of 6581734 as the same fix resolves both. + + +public class Test6581734 { + + private String poolName = "CMS"; + private String collectorName = "ConcurrentMarkSweep"; + + public static void main(String [] args) { + + Test6581734 t = null; + if (args.length==2) { + t = new Test6581734(args[0], args[1]); + } else { + System.out.println("Defaulting to monitor CMS pool and collector."); + t = new Test6581734(); + } + t.run(); + } + + public Test6581734(String pool, String collector) { + poolName = pool; + collectorName = collector; + } + + public Test6581734() { + } + + public void run() { + // Use some memory, enough that we expect collections should + // have happened. + // Must run with options to ensure no stop the world full GC, + // but e.g. at least one CMS cycle. + allocationWork(300*1024*1024); + System.out.println("Done allocationWork"); + + // Verify some non-zero results are stored. + List pools = ManagementFactory.getMemoryPoolMXBeans(); + int poolsFound = 0; + int poolsWithStats = 0; + for (int i=0; i collectors = ManagementFactory.getGarbageCollectorMXBeans(); + int collectorsFound = 0; + int collectorsWithTime= 0; + for (int i=0; i 0) { + collectorsWithTime++; + } + } + } + // verify: + if (poolsWithStats < poolsFound) { + throw new RuntimeException("pools found with zero stats"); + } + + if (collectorsWithTime>Loader2>> "+msg); + } + + protected Class findClass2(String name) throws ClassNotFoundException { + print("Fetching the implementation of "+name); + int old = _recur; + try { + FileInputStream fi = new FileInputStream(name+".impl2"); + byte result[] = new byte[fi.available()]; + fi.read(result); + + print("DefineClass1 on "+name); + _recur++; + Class clazz = defineClass(name, result, 0, result.length); + _recur = old; + print("Returning newly loaded class."); + return clazz; + } catch (Exception e) { + _recur = old; + print("Not found on disk."); + // If we caught an exception, either the class was not found or + // it was unreadable by our process. + return null; + //throw new ClassNotFoundException(e.toString()); + } + } + + protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + // Attempt a disk load first + Class c = findClass2(name); + if( c == null ) { + // check if the class has already been loaded + print("Checking for prior loaded class "+name); + c = findLoadedClass(name); + print("Letting super-loader load "+name); + int old = _recur; + _recur++; + c = super.loadClass(name, false); + _recur=old; + } + if (resolve) { print("Resolving class "+name); resolveClass(c); } + print("Returning clazz "+c.getClassLoader()+":"+name); + return c; + } +} diff --git a/hotspot/test/runtime/6626217/Test6626217.sh b/hotspot/test/runtime/6626217/Test6626217.sh new file mode 100644 index 00000000000..88c3c5bf580 --- /dev/null +++ b/hotspot/test/runtime/6626217/Test6626217.sh @@ -0,0 +1,119 @@ +# +# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + + +# @test @(#)Test6626217.sh +# @bug 6626217 +# @summary Loader-constraint table allows arrays instead of only the base-classes +# @run shell Test6626217.sh +# + +if [ "${TESTSRC}" = "" ] + then TESTSRC=. +fi + +if [ "${TESTJAVA}" = "" ] +then + PARENT=`dirname \`which java\`` + TESTJAVA=`dirname ${PARENT}` + echo "TESTJAVA not set, selecting " ${TESTJAVA} + echo "If this is incorrect, try setting the variable manually." +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +BIT_FLAG="" + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + SunOS | Linux ) + NULL=/dev/null + PS=":" + FS="/" + RM=/bin/rm + CP=/bin/cp + MV=/bin/mv + ## for solaris, linux it's HOME + FILE_LOCATION=$HOME + if [ -f ${FILE_LOCATION}${FS}JDK64BIT -a ${OS} = "SunOS" ] + then + BIT_FLAG=`cat ${FILE_LOCATION}${FS}JDK64BIT` + fi + ;; + Windows_* ) + NULL=NUL + PS=";" + FS="\\" + RM=rm + CP=cp + MV=mv + ;; + * ) + echo "Unrecognized system!" + exit 1; + ;; +esac + +JEMMYPATH=${CPAPPEND} +CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH + +THIS_DIR=`pwd` + +JAVA=${TESTJAVA}${FS}bin${FS}java +JAVAC=${TESTJAVA}${FS}bin${FS}javac + +${JAVA} ${BIT_FLAG} -version + +# Current directory is scratch directory, copy all the test source there +# (for the subsequent moves to work). +${CP} ${TESTSRC}${FS}* ${THIS_DIR} + +# A Clean Compile: this line will probably fail within jtreg as have a clean dir: +${RM} -f *.class *.impl many_loader.java + +# Compile all the usual suspects, including the default 'many_loader' +${CP} many_loader1.java.foo many_loader.java +${JAVAC} -source 1.4 -target 1.4 -Xlint *.java + +# Rename the class files, so the custom loader (and not the system loader) will find it +${MV} from_loader2.class from_loader2.impl2 + +# Compile the next version of 'many_loader' +${MV} many_loader.class many_loader.impl1 +${CP} many_loader2.java.foo many_loader.java +${JAVAC} -source 1.4 -target 1.4 -Xlint many_loader.java + +# Rename the class file, so the custom loader (and not the system loader) will find it +${MV} many_loader.class many_loader.impl2 +${MV} many_loader.impl1 many_loader.class +${RM} many_loader.java + +${JAVA} ${BIT_FLAG} -Xverify -Xint -cp . bug_21227 >test.out 2>&1 +grep "loader constraint" test.out +exit $? + diff --git a/hotspot/test/runtime/6626217/You_Have_Been_P0wned.java b/hotspot/test/runtime/6626217/You_Have_Been_P0wned.java new file mode 100644 index 00000000000..2bebbe0590c --- /dev/null +++ b/hotspot/test/runtime/6626217/You_Have_Been_P0wned.java @@ -0,0 +1,11 @@ + +// I can cast any old thing I want to this type object: +public class You_Have_Been_P0wned { + // Make a bunch of int-fields so I can peek & poke it + int _a; + int _b; + int _c; + int _d; + +} + diff --git a/hotspot/test/runtime/6626217/bug_21227.java b/hotspot/test/runtime/6626217/bug_21227.java new file mode 100644 index 00000000000..18d30c41fb0 --- /dev/null +++ b/hotspot/test/runtime/6626217/bug_21227.java @@ -0,0 +1,61 @@ + +import java.lang.reflect.*; +import java.security.*; + +abstract public class bug_21227 { + + // Jam anything you want in here, it will be cast to a You_Have_Been_P0wned + public static Object _p0wnee; + + public static void main(String argv[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException { + System.out.println("Warmup"); + + // Make a Class 'many_loader' under the default loader + bug_21227 bug = new many_loader(); + + // Some classes under a new Loader, LOADER2, including another version of 'many_loader' + ClassLoader LOADER2 = new Loader2(); + Class clazz2 = LOADER2.loadClass("from_loader2"); + IFace iface = (IFace)clazz2.newInstance(); + + // Set the victim, a String of length 6 + String s = "victim"; + _p0wnee = s; + + // Go cast '_p0wnee' to type You_Have_Been_P0wned + many_loader[] x2 = bug.make(iface); + + many_loader b = x2[0]; + + // Make it clear that the runtime type many_loader (what we get from the + // array X2) varies from the static type of many_loader. + Class cl1 = b.getClass(); + ClassLoader ld1 = cl1.getClassLoader(); + Class cl2 = many_loader.class; + ClassLoader ld2 = cl2.getClassLoader(); + System.out.println("bug.make() "+ld1+":"+cl1); + System.out.println("many_loader "+ld2+":"+cl2); + + // Read the victims guts out + You_Have_Been_P0wned q = b._p0wnee; + System.out.println("q._a = 0x"+Integer.toHexString(q._a)); + System.out.println("q._b = 0x"+Integer.toHexString(q._b)); + System.out.println("q._c = 0x"+Integer.toHexString(q._c)); + System.out.println("q._d = 0x"+Integer.toHexString(q._d)); + + System.out.println("I will now crash the VM:"); + // On 32-bit HotSpot Java6 this sets the victim String length shorter, then crashes the VM + //q._c = 3; + q._a = -1; + + System.out.println(s); + + } + + // I need to compile (hence call in a loop) a function which returns a value + // loaded from classloader other than the system one. The point of this + // call is to give me an abstract 'hook' into a function loaded with a + // foreign loader. + public abstract many_loader[] make( IFace iface ); // abstract factory +} + diff --git a/hotspot/test/runtime/6626217/from_loader2.java b/hotspot/test/runtime/6626217/from_loader2.java new file mode 100644 index 00000000000..6421f2a3c65 --- /dev/null +++ b/hotspot/test/runtime/6626217/from_loader2.java @@ -0,0 +1,9 @@ +// A simple class to extend an abstract class and get loaded with different +// loaders. This class is loaded via LOADER2. +public class from_loader2 implements IFace { + public many_loader[] gen() { + many_loader[] x = new many_loader[1]; + x[0] = new many_loader(); + return x; + } +} diff --git a/hotspot/test/runtime/6626217/many_loader1.java.foo b/hotspot/test/runtime/6626217/many_loader1.java.foo new file mode 100644 index 00000000000..b5295a370c0 --- /dev/null +++ b/hotspot/test/runtime/6626217/many_loader1.java.foo @@ -0,0 +1,23 @@ +// A simple class to extend an abstract class and get loaded with different +// loaders. This class is loaded via LOADER1. A similar named class will +// be loaded via LOADER2. +public class many_loader extends bug_21227 { + public You_Have_Been_P0wned _p0wnee; + + // I need to compile (hence call in a loop) a function which returns a value + // loaded from classloader other than the system one. The point of this + // call is to give me an abstract 'hook' into a function loaded with a + // foreign loader. + + // The original 'make(boolean)' returns a bug_21227. The VM will inject a + // synthetic method to up-cast the returned 'from_loader1' into a + // 'bug_21227'. + public many_loader[] make( IFace iface ) { + // This function needs to return a value known to be loaded from LOADER2. + // Since I need to use a yet different loader, I need to make an unknown + // foreign call. In this case I'll be using an interface to make the + // unknown call, with but a single implementor so the compiler can do the + // upcast statically. + return iface==null ? null : iface.gen(); + } +} diff --git a/hotspot/test/runtime/6626217/many_loader2.java.foo b/hotspot/test/runtime/6626217/many_loader2.java.foo new file mode 100644 index 00000000000..1b72132a2a8 --- /dev/null +++ b/hotspot/test/runtime/6626217/many_loader2.java.foo @@ -0,0 +1,19 @@ +// A simple class to extend an abstract class and get loaded with different +// loaders. This class is loaded via LOADER2. A similar named class will +// be loaded via LOADER1. +public class many_loader extends bug_21227 { + final Object _ref_to_be_p0wned; + + many_loader() { + _ref_to_be_p0wned = bug_21227._p0wnee; + System.out.println("Gonna hack this thing: " + _ref_to_be_p0wned.toString() ); + } + + // I need to compile (hence call in a loop) a function which returns a value + // loaded from classloader other than the system one. The point of this + // call is to give me an abstract 'hook' into a function loaded with a + // foreign loader. + public many_loader[] make( IFace iface ) { + throw new Error("do not call me"); + } +} diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 4e045e1be2a..e7b0a593feb 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -82,3 +82,7 @@ d42c4acb6424a094bdafe2ad9c8c1c7ca7fb7b7e jdk7-b104 3233b9a4c12ef2663a356d08bb141c02736c7f49 jdk7-b105 5ba8469212a6cab95ca652eea414b753be7d245a jdk7-b106 20ee37c1372a3eaefa49b426c6eb68a2e8f5d6e2 jdk7-b107 +7d379f8934caf255f53def1310c0ef0f1b512601 jdk7-b108 +0f382d6120fc07aed2209484a42458cabf405916 jdk7-b109 +d422dbdd09766269344b796b3a46a5b3f74557e1 jdk7-b110 +8106c747067c905d814a737a57fea0e29057b33f jdk7-b111 diff --git a/jaxp/jaxp.properties b/jaxp/jaxp.properties index de35af2c1fe..296ed0b08f2 100644 --- a/jaxp/jaxp.properties +++ b/jaxp/jaxp.properties @@ -25,12 +25,13 @@ drops.master.copy.base=${drops.dir} -jaxp_src.bundle.name=jdk7-jaxp-m7.zip -jaxp_src.bundle.md5.checksum=22e95fbdb9fb7d8b6b6fc0a1d76d1fbd +jaxp_src.bundle.name=jaxp-1_4_4.zip +jaxp_src.bundle.md5.checksum=2c40a758392c4abf2d59f355240df46a jaxp_src.master.bundle.dir=${drops.master.copy.base} -jaxp_src.master.bundle.url.base=https://jaxp.dev.java.net/files/documents/913/150785 +jaxp_src.master.bundle.url.base=https://jaxp.dev.java.net/files/documents/913/152561 -#jaxp_tests.bundle.name=jdk7-jaxp-tests-2009_08_28.zip +#jaxp_tests.bundle.name=jaxp-unittests-1_4_4.zip +#jaxp_tests.bundle.md5.checksum=51845e38b02920cf5374d0331ab3a4ee #jaxp_tests.master.bundle.dir=${drops.master.copy.base} -#jaxp_tests.master.bundle.url.base=https://jaxp.dev.java.net/files/documents/913/147490 +#jaxp_tests.master.bundle.url.base=https://jaxp.dev.java.net/files/documents/913/152562 diff --git a/jaxp/make/jprt.properties b/jaxp/make/jprt.properties index 2449f9f084e..c95c9d06869 100644 --- a/jaxp/make/jprt.properties +++ b/jaxp/make/jprt.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,31 +24,13 @@ # # Properties for jprt -jprt.tools.default.release=jdk1.7.0 -# Specific platform list -jprt.build.platforms=\ -solaris_sparc_5.10,\ -solaris_sparcv9_5.10,\ -solaris_i586_5.10,\ -solaris_x64_5.10,\ -linux_i586_2.6,\ -linux_x64_2.6,\ -windows_i586_5.0,\ -windows_x64_5.2 +# Use whatever release that the submitted job requests +jprt.tools.default.release=${jprt.submit.release} -# The different build flavors we want +# The different build flavors we want, we override here so we just get these 2 jprt.build.flavors=product,fastdebug -# Explicitly designate what the 32bit match is for the 64bit build -jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10 -jprt.solaris_sparcv9_5.10.build.platform.match32=solaris_sparc_5.10 -jprt.solaris_x64.build.platform.match32=solaris_i586_5.10 -jprt.solaris_x64_5.10.build.platform.match32=solaris_i586_5.10 - -# Standard list of jprt test targets for this workspace -jprt.test.targets= - -# Directories needing to exclude from source bundles -jprt.bundle.exclude.src.dirs=build dist +# Directories to be excluded from the source bundles +jprt.bundle.exclude.src.dirs=build dist webrev diff --git a/jaxws/.hgtags b/jaxws/.hgtags index c0a5c32e8d3..7d3a0bc9d25 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -82,3 +82,7 @@ bbc4cce6c20aeca4862804a6e8315a2350d43633 jdk7-b104 39eb4f3031f4a985664cace00fca3bd1eab1e0aa jdk7-b105 bc45ccc5bcca6cbe4ea433e279d4a93b06ab38c6 jdk7-b106 017612ea6af417a5e378619704da01bb3a583bdb jdk7-b107 +b1ca39340238a239ba6d8489ad5315215e1366ca jdk7-b108 +4f626e0d70bda68c76bbd0e89d2bc2407f979736 jdk7-b109 +95ecac35fb11530752bd0404c9bf02bcfb30990e jdk7-b110 +2575ebca96c7fb1b78f6ae025a97321210aba309 jdk7-b111 diff --git a/jaxws/jaxws.properties b/jaxws/jaxws.properties index 6e8e3a3b94e..3314617b2d4 100644 --- a/jaxws/jaxws.properties +++ b/jaxws/jaxws.properties @@ -25,15 +25,15 @@ drops.master.copy.base=${drops.dir} -jaxws_src.bundle.name=jdk7-jaxws-b100.zip -jaxws_src.bundle.md5.checksum=e4fea255c6222b118bb1d0d3054d36e1 +jaxws_src.bundle.name= jdk7-jaxws2_2-2010_08_19.zip +jaxws_src.bundle.md5.checksum=8775ccefd3b4fa2dde5155ec4b7e4ceb jaxws_src.master.bundle.dir=${drops.master.copy.base} -jaxws_src.master.bundle.url.base=https://jax-ws.dev.java.net/files/documents/4202/150896 +jaxws_src.master.bundle.url.base=https://jax-ws.dev.java.net/files/documents/4202/152532 -jaf_src.bundle.name=jdk7-jaf-2009_08_28.zip -jaf_src.bundle.md5.checksum=eb8cb7a4a7f14e211fbe2354878a2472 +jaf_src.bundle.name=jdk7-jaf-2010_08_19.zip +jaf_src.bundle.md5.checksum=18d15dfd71117daadb332af003d08212 jaf_src.master.bundle.dir=${drops.master.copy.base} -jaf_src.master.bundle.url.base=http://kenai.com/projects/jdk7-drops/downloads/download +jaf_src.master.bundle.url.base=https://jax-ws.dev.java.net/files/documents/4202/152336 #jaxws_tests.bundle.name=jdk7-jaxws-tests-2009_08_28.zip #jaxws_tests.master.bundle.dir=${drops.master.copy.base} diff --git a/jaxws/make/jprt.properties b/jaxws/make/jprt.properties index 2449f9f084e..c95c9d06869 100644 --- a/jaxws/make/jprt.properties +++ b/jaxws/make/jprt.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,31 +24,13 @@ # # Properties for jprt -jprt.tools.default.release=jdk1.7.0 -# Specific platform list -jprt.build.platforms=\ -solaris_sparc_5.10,\ -solaris_sparcv9_5.10,\ -solaris_i586_5.10,\ -solaris_x64_5.10,\ -linux_i586_2.6,\ -linux_x64_2.6,\ -windows_i586_5.0,\ -windows_x64_5.2 +# Use whatever release that the submitted job requests +jprt.tools.default.release=${jprt.submit.release} -# The different build flavors we want +# The different build flavors we want, we override here so we just get these 2 jprt.build.flavors=product,fastdebug -# Explicitly designate what the 32bit match is for the 64bit build -jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10 -jprt.solaris_sparcv9_5.10.build.platform.match32=solaris_sparc_5.10 -jprt.solaris_x64.build.platform.match32=solaris_i586_5.10 -jprt.solaris_x64_5.10.build.platform.match32=solaris_i586_5.10 - -# Standard list of jprt test targets for this workspace -jprt.test.targets= - -# Directories needing to exclude from source bundles -jprt.bundle.exclude.src.dirs=build dist +# Directories to be excluded from the source bundles +jprt.bundle.exclude.src.dirs=build dist webrev diff --git a/jdk/.hgtags b/jdk/.hgtags index c06fc47e775..e69a21ab6c0 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -82,3 +82,7 @@ d58354a69011f3d3354765fa3167567c4c4a9612 jdk7-b101 3b0abcb512807bb6f6d27755bc50103211bde6ee jdk7-b105 b91ef6b60f4e19bf4592c6dd594c9bac62487519 jdk7-b106 882103f334bb23745d3fd70fb7928c347478b0f4 jdk7-b107 +17a5d84b75610255a3527e8ede1da19c91ba7a7e jdk7-b108 +ab0d3f54a63f2aadfcdd2e14b81f79362ce454e2 jdk7-b109 +176586cd040e4dd17a5ff6e91f72df10d7442453 jdk7-b110 +fb63a2688db807a73e2a3de7d9bab298f1bff0e8 jdk7-b111 diff --git a/jdk/make/com/Makefile b/jdk/make/com/Makefile index baf56b3ddb0..37472ea3f3a 100644 --- a/jdk/make/com/Makefile +++ b/jdk/make/com/Makefile @@ -31,7 +31,7 @@ BUILDDIR = .. PRODUCT = com include $(BUILDDIR)/common/Defs.gmk -SUBDIRS = sun +SUBDIRS = sun oracle include $(BUILDDIR)/common/Subdirs.gmk all build clean clobber:: diff --git a/jdk/make/com/oracle/Makefile b/jdk/make/com/oracle/Makefile new file mode 100644 index 00000000000..7c70dc78270 --- /dev/null +++ b/jdk/make/com/oracle/Makefile @@ -0,0 +1,34 @@ +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +BUILDDIR = ../.. +PRODUCT = oracle +include $(BUILDDIR)/common/Defs.gmk + +SUBDIRS = net +include $(BUILDDIR)/common/Subdirs.gmk + +all build clean clobber:: + $(SUBDIRS-loop) diff --git a/corba/make/common/shared/Compiler.gmk b/jdk/make/com/oracle/net/Makefile similarity index 67% rename from corba/make/common/shared/Compiler.gmk rename to jdk/make/com/oracle/net/Makefile index 0d5945542d8..5fd30761699 100644 --- a/corba/make/common/shared/Compiler.gmk +++ b/jdk/make/com/oracle/net/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,25 +23,17 @@ # questions. # +BUILDDIR = ../../.. +PRODUCT = oracle +include $(BUILDDIR)/common/Defs.gmk + # -# Compiler settings for all platforms and the default compiler for each. +# Files to compile # +AUTO_FILES_JAVA_DIRS = com/oracle/net -# Windows uses Microsoft compilers by default -ifeq ($(PLATFORM), windows) - override CC_VERSION = msvc -endif - -# Solaris uses Sun Studio compilers by default -ifeq ($(PLATFORM), solaris) - override CC_VERSION = sun -endif - -# Linux uses GNU compilers by default -ifeq ($(PLATFORM), linux) - override CC_VERSION = gcc -endif - -# Get the compiler specific settings -include $(BUILDDIR)/common/shared/Compiler-$(CC_VERSION).gmk +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk diff --git a/jdk/make/common/Release.gmk b/jdk/make/common/Release.gmk index bc40dcc9725..b8e95bea2ee 100644 --- a/jdk/make/common/Release.gmk +++ b/jdk/make/common/Release.gmk @@ -573,13 +573,13 @@ $(NOT_RT_JAR_LIST): FRC $(ECHO) "sun/jvmstat/" >> $@ $(ECHO) "sun/nio/cs/ext/" >> $@ $(ECHO) "sun/awt/HKSCS.class" >> $@ - $(ECHO) "sun/awt/motif/X11GB2312$Decoder.class" >> $@ - $(ECHO) "sun/awt/motif/X11GB2312$Encoder.class" >> $@ + $(ECHO) "sun/awt/motif/X11GB2312\$$Decoder.class" >> $@ + $(ECHO) "sun/awt/motif/X11GB2312\$$Encoder.class" >> $@ $(ECHO) "sun/awt/motif/X11GB2312.class" >> $@ - $(ECHO) "sun/awt/motif/X11GBK$Encoder.class" >> $@ + $(ECHO) "sun/awt/motif/X11GBK\$$Encoder.class" >> $@ $(ECHO) "sun/awt/motif/X11GBK.class" >> $@ - $(ECHO) "sun/awt/motif/X11KSC5601$Decoder.class" >> $@ - $(ECHO) "sun/awt/motif/X11KSC5601$Encoder.class" >> $@ + $(ECHO) "sun/awt/motif/X11KSC5601\$$Decoder.class" >> $@ + $(ECHO) "sun/awt/motif/X11KSC5601\$$Encoder.class" >> $@ $(ECHO) "sun/awt/motif/X11KSC5601.class" >> $@ $(ECHO) "sun/rmi/rmic/" >> $@ $(ECHO) "sun/tools/asm/" >> $@ diff --git a/jdk/make/common/shared/Compiler-sun.gmk b/jdk/make/common/shared/Compiler-sun.gmk index 712b4ffe52e..9de1b499124 100644 --- a/jdk/make/common/shared/Compiler-sun.gmk +++ b/jdk/make/common/shared/Compiler-sun.gmk @@ -61,6 +61,7 @@ endif # Get compiler version _CC_VER :=$(shell $(CC) -V 2>&1 | $(HEAD) -n 1) CC_VER :=$(call GetVersion,"$(_CC_VER)") +CC_MINORVER :=$(call MinorVersion,$(CC_VER)) # Name of compilers being used COMPILER_VERSION-5.7 = SS10 @@ -69,8 +70,10 @@ COMPILER_VERSION-5.8 = SS11 COMPILER_NAME-5.8 = Sun Studio 11 COMPILER_VERSION-5.9 = SS12 COMPILER_NAME-5.9 = Sun Studio 12 -COMPILER_VERSION-5.10 = SS13 -COMPILER_NAME-5.10 = Sun Studio 13 +COMPILER_VERSION-5.10 = SS12u1 +COMPILER_NAME-5.10 = Sun Studio 12 Update 1 +COMPILER_VERSION-5.11 = OSS12u2 +COMPILER_NAME-5.11 = Oracle Solaris Studio 12 Update 2 COMPILER_VERSION = $(COMPILER_VERSION-$(CC_VER)) COMPILER_NAME = $(COMPILER_NAME-$(CC_VER)) @@ -112,8 +115,8 @@ ifeq ($(ARCH_FAMILY), i586) XARCH_OPTION_OLD/64 += -xarch=amd64 LINT_XARCH_OPTION_OLD/64 += -Xarch=amd64 endif -# Pick the options we want based on the compiler being used. -ifeq ($(shell expr $(CC_VER) \>= 5.9), 1) +# Pick the options we want based on the compiler being used. (5.9 or newer) +ifeq ($(shell expr $(CC_MINORVER) \>= 9), 1) XARCH_OPTION/32 = $(XARCH_OPTION_NEW/32) XARCH_OPTION/64 = $(XARCH_OPTION_NEW/64) LINT_XARCH_OPTION/32 = $(LINT_XARCH_OPTION_NEW/32) diff --git a/jdk/make/common/shared/Defs-versions.gmk b/jdk/make/common/shared/Defs-versions.gmk index 870ae229f3b..91fe4be8056 100644 --- a/jdk/make/common/shared/Defs-versions.gmk +++ b/jdk/make/common/shared/Defs-versions.gmk @@ -120,10 +120,10 @@ ifeq ($(PLATFORM), solaris) else REQUIRED_FREE_SPACE = 1040000 endif - REQUIRED_COMPILER_NAME = Sun Studio 12 - REQUIRED_COMPILER_VERSION = SS12 + REQUIRED_COMPILER_NAME = Sun Studio 12 Update 1 + REQUIRED_COMPILER_VERSION = SS12u1 ifeq ($(CC_VERSION),sun) - REQUIRED_CC_VER = 5.9 + REQUIRED_CC_VER = 5.10 endif ifeq ($(CC_VERSION),gcc) REQUIRED_CC_VER = 3.4.3 @@ -145,7 +145,7 @@ ifeq ($(PLATFORM), linux) REQUIRED_CC_VER = 4.3.0 endif ifeq ($(CC_VERSION),sun) - REQUIRED_CC_VER = 5.9 + REQUIRED_CC_VER = 5.10 endif endif diff --git a/jdk/make/common/shared/Defs-windows.gmk b/jdk/make/common/shared/Defs-windows.gmk index 121cd94ea49..ac9daf4cd6c 100644 --- a/jdk/make/common/shared/Defs-windows.gmk +++ b/jdk/make/common/shared/Defs-windows.gmk @@ -89,7 +89,7 @@ define FullPath $(shell $(CYGPATH_CMD) $1 2> $(DEV_NULL)) endef define OptFullPath -$(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1"; else echo "$1"; fi) +$(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1" 2> $(DEV_NULL); else echo "$1"; fi) endef else # Temporary until we upgrade to MKS 8.7, MKS pwd returns mixed mode path diff --git a/jdk/make/common/shared/Defs.gmk b/jdk/make/common/shared/Defs.gmk index 3ccab90196c..ed32779c8c2 100644 --- a/jdk/make/common/shared/Defs.gmk +++ b/jdk/make/common/shared/Defs.gmk @@ -136,15 +136,20 @@ define GetVersion $(shell echo $1 | sed -e 's@[^0-9]*\([0-9][0-9]*\.[0-9][.0-9]*\).*@\1@' ) endef +# Return one part of the version numbers, watch out for non digits. +define VersionWord # Number Version +$(word $1,$(subst ., ,$(subst -, ,$2))) +endef + # Given a major.minor.micro version, return the major, minor, or micro number define MajorVersion -$(if $(word 1, $(subst ., ,$1)),$(word 1, $(subst ., ,$1)),0) +$(if $(call VersionWord,1,$1),$(call VersionWord,1,$1),0) endef define MinorVersion -$(if $(word 2, $(subst ., ,$1)),$(word 2, $(subst ., ,$1)),0) +$(if $(call VersionWord,2,$1),$(call VersionWord,2,$1),0) endef define MicroVersion -$(if $(word 3, $(subst ., ,$1)),$(word 3, $(subst ., ,$1)),0) +$(if $(call VersionWord,3,$1),$(call VersionWord,3,$1),0) endef # Macro that returns missing, same, newer, or older $1=version $2=required diff --git a/jdk/make/docs/NON_CORE_PKGS.gmk b/jdk/make/docs/NON_CORE_PKGS.gmk index 6639eecf893..180241483c1 100644 --- a/jdk/make/docs/NON_CORE_PKGS.gmk +++ b/jdk/make/docs/NON_CORE_PKGS.gmk @@ -91,6 +91,8 @@ SCTPAPI_PKGS = com.sun.nio.sctp TRACING_PKGS = com.sun.tracing \ com.sun.tracing.dtrace +ORACLENET_PKGS = com.oracle.net + # non-core packages in rt.jar NON_CORE_PKGS = $(DOMAPI_PKGS) \ $(MGMT_PKGS) \ @@ -101,5 +103,6 @@ NON_CORE_PKGS = $(DOMAPI_PKGS) \ $(HTTPSERVER_PKGS) \ $(SMARTCARDIO_PKGS) \ $(TRACING_PKGS) \ - $(SCTPAPI_PKGS) + $(SCTPAPI_PKGS) \ + $(ORACLENET_PKGS) diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index 416eeb343d0..d9af3c10fda 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -183,10 +183,22 @@ JAVA_JAVA_java = \ java/util/MissingFormatWidthException.java \ java/util/UnknownFormatConversionException.java \ java/util/UnknownFormatFlagsException.java \ + java/util/IllformedLocaleException.java \ java/util/FormatterClosedException.java \ java/util/ListResourceBundle.java \ sun/util/EmptyListResourceBundle.java \ java/util/Locale.java \ + sun/util/locale/AsciiUtil.java \ + sun/util/locale/BaseLocale.java \ + sun/util/locale/Extension.java \ + sun/util/locale/InternalLocaleBuilder.java \ + sun/util/locale/LanguageTag.java \ + sun/util/locale/LocaleExtensions.java \ + sun/util/locale/LocaleObjectCache.java \ + sun/util/locale/LocaleSyntaxException.java \ + sun/util/locale/ParseStatus.java \ + sun/util/locale/StringTokenIterator.java \ + sun/util/locale/UnicodeLocaleExtension.java \ java/util/LocaleISOData.java \ sun/util/LocaleServiceProviderPool.java \ sun/util/LocaleDataMetaInfo.java \ diff --git a/jdk/make/java/net/FILES_c.gmk b/jdk/make/java/net/FILES_c.gmk index 642244915af..29ce70a6e68 100644 --- a/jdk/make/java/net/FILES_c.gmk +++ b/jdk/make/java/net/FILES_c.gmk @@ -39,10 +39,6 @@ FILES_c = \ ResolverConfigurationImpl.c \ DefaultProxySelector.c -ifeq ($(PLATFORM), solaris) - FILES_c += SdpProvider.c -endif - ifeq ($(PLATFORM), linux) FILES_c += linux_close.c endif diff --git a/jdk/make/java/net/Makefile b/jdk/make/java/net/Makefile index 0021087cbcf..db034f2511e 100644 --- a/jdk/make/java/net/Makefile +++ b/jdk/make/java/net/Makefile @@ -44,6 +44,8 @@ ifeq ($(PLATFORM), windows) endif FILES_c += NTLMAuthSequence.c FILES_c += NetworkInterface_winXP.c +else + FILES_c += SdpSupport.c endif FILES_export = \ @@ -84,7 +86,8 @@ endif # # Find platform specific native code # -vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http/ntlm $(PLATFORM_SRC)/native/sun/net/spi +vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http/ntlm \ + $(PLATFORM_SRC)/native/sun/net/sdp $(PLATFORM_SRC)/native/sun/net/spi # # Include rules diff --git a/jdk/make/java/net/mapfile-vers b/jdk/make/java/net/mapfile-vers index fbcf905d173..0e9a46755d4 100644 --- a/jdk/make/java/net/mapfile-vers +++ b/jdk/make/java/net/mapfile-vers @@ -88,9 +88,10 @@ SUNWprivate_1.1 { Java_java_net_PlainDatagramSocketImpl_setTimeToLive; Java_sun_net_dns_ResolverConfigurationImpl_localDomain0; Java_sun_net_dns_ResolverConfigurationImpl_fallbackDomain0; + Java_sun_net_sdp_SdpSupport_convert0; + Java_sun_net_sdp_SdpSupport_create0; Java_sun_net_spi_DefaultProxySelector_init; Java_sun_net_spi_DefaultProxySelector_getSystemProxy; - Java_sun_net_spi_SdpProvider_convert; NET_AllocSockaddr; NET_SockaddrToInetAddress; NET_SockaddrEqualsInetAddress; diff --git a/jdk/make/java/nio/FILES_java.gmk b/jdk/make/java/nio/FILES_java.gmk index 4ad955d87aa..e49d5267a47 100644 --- a/jdk/make/java/nio/FILES_java.gmk +++ b/jdk/make/java/nio/FILES_java.gmk @@ -83,6 +83,7 @@ FILES_src = \ java/nio/file/ClosedFileSystemException.java \ java/nio/file/ClosedWatchServiceException.java \ java/nio/file/CopyOption.java \ + java/nio/file/DirectoryIteratorException.java \ java/nio/file/DirectoryNotEmptyException.java \ java/nio/file/DirectoryStream.java \ java/nio/file/FileAlreadyExistsException.java \ @@ -199,6 +200,7 @@ FILES_src = \ sun/nio/ch/PipeImpl.java \ sun/nio/ch/PollArrayWrapper.java \ sun/nio/ch/Reflect.java \ + sun/nio/ch/Secrets.java \ sun/nio/ch/SelectionKeyImpl.java \ sun/nio/ch/SelectorImpl.java \ sun/nio/ch/SelectorProviderImpl.java \ diff --git a/jdk/make/java/nio/mapfile-linux b/jdk/make/java/nio/mapfile-linux index 13cc1cd01ec..c3645c5ed05 100644 --- a/jdk/make/java/nio/mapfile-linux +++ b/jdk/make/java/nio/mapfile-linux @@ -89,7 +89,7 @@ SUNWprivate_1.1 { Java_sun_nio_ch_IOUtil_drain; Java_sun_nio_ch_IOUtil_fdVal; Java_sun_nio_ch_IOUtil_initIDs; - Java_sun_nio_ch_IOUtil_initPipe; + Java_sun_nio_ch_IOUtil_makePipe; Java_sun_nio_ch_IOUtil_randomBytes; Java_sun_nio_ch_IOUtil_setfdVal; Java_sun_nio_ch_NativeThread_current; diff --git a/jdk/make/java/nio/mapfile-solaris b/jdk/make/java/nio/mapfile-solaris index 2b80e4e801e..e0dff0a32f3 100644 --- a/jdk/make/java/nio/mapfile-solaris +++ b/jdk/make/java/nio/mapfile-solaris @@ -76,7 +76,7 @@ SUNWprivate_1.1 { Java_sun_nio_ch_IOUtil_drain; Java_sun_nio_ch_IOUtil_fdVal; Java_sun_nio_ch_IOUtil_initIDs; - Java_sun_nio_ch_IOUtil_initPipe; + Java_sun_nio_ch_IOUtil_makePipe; Java_sun_nio_ch_IOUtil_randomBytes; Java_sun_nio_ch_IOUtil_setfdVal; Java_sun_nio_ch_NativeThread_current; diff --git a/jdk/make/java/redist/Makefile b/jdk/make/java/redist/Makefile index 08cee4a3301..6f86be97f14 100644 --- a/jdk/make/java/redist/Makefile +++ b/jdk/make/java/redist/Makefile @@ -43,6 +43,7 @@ SERVER_LOCATION = server CLIENT_LOCATION = client DB_SUFFIX = _db +DTRACE_SUFFIX = _dtrace ifeq ($(PLATFORM), windows) LIB_LOCATION = $(BINDIR) @@ -56,6 +57,7 @@ JVMMAP_NAME = $(LIB_PREFIX)jvm.map JVMPDB_NAME = $(LIB_PREFIX)jvm.pdb LIBJSIG_NAME = $(LIB_PREFIX)jsig.$(LIBRARY_SUFFIX) JVMDB_NAME = $(LIB_PREFIX)jvm$(DB_SUFFIX).$(LIBRARY_SUFFIX) +JVMDTRACE_NAME = $(LIB_PREFIX)jvm$(DTRACE_SUFFIX).$(LIBRARY_SUFFIX) CLASSSHARINGDATA_DIR = $(BUILDDIR)/tools/sharing @@ -161,6 +163,12 @@ IMPORT_LIST += \ ifeq ($(PLATFORM), solaris) IMPORT_LIST += $(LIB_LOCATION)/$(SERVER_LOCATION)/$(JVMDB_NAME) +# The conditional can be removed when import JDKs contain these files. +ifneq ($(wildcard $(HOTSPOT_SERVER_PATH)/$(JVMDTRACE_NAME)),) + IMPORT_LIST += $(LIB_LOCATION)/$(SERVER_LOCATION)/$(JVMDTRACE_NAME) +else + $(warning WARNING: $(HOTSPOT_SERVER_PATH)/$(JVMDB_NAME) not found!) +endif endif ifneq ($(ZERO_BUILD), true) @@ -171,14 +179,29 @@ IMPORT_LIST += $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(LIBJSIG_NAME) ifeq ($(PLATFORM), solaris) # solaris vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv solaris -ifeq ($(ARCH), sparc) - IMPORT_LIST += $(LIB_LOCATION)/$(SERVER_LOCATION)/64/$(JVMDB_NAME) -endif - IMPORT_LIST += $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(JVMDB_NAME) -ifeq ($(ARCH), sparc) +# The conditional can be removed when import JDKs contain these files. +ifneq ($(wildcard $(HOTSPOT_CLIENT_PATH)/$(JVMDTRACE_NAME)),) + IMPORT_LIST += $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(JVMDTRACE_NAME) IMPORT_LIST += $(LIB_LOCATION)/$(CLIENT_LOCATION)/64/$(JVMDB_NAME) + IMPORT_LIST += $(LIB_LOCATION)/$(CLIENT_LOCATION)/64/$(JVMDTRACE_NAME) +else + $(warning WARNING: $(HOTSPOT_CLIENT_PATH)/$(JVMDTRACE_NAME) not found!) +endif + +# The conditional can be removed when import JDKs contain these files. +ifneq ($(wildcard $(HOTSPOT_SERVER_PATH)/64/$(JVMDB_NAME)),) + IMPORT_LIST += $(LIB_LOCATION)/$(SERVER_LOCATION)/64/$(JVMDB_NAME) +else + $(warning WARNING: $(HOTSPOT_SERVER_PATH)/64/$(JVMDB_NAME) not found!) +endif + +# The conditional can be removed when import JDKs contain these files. +ifneq ($(wildcard $(HOTSPOT_SERVER_PATH)/64/$(JVMDTRACE_NAME)),) + IMPORT_LIST += $(LIB_LOCATION)/$(SERVER_LOCATION)/64/$(JVMDTRACE_NAME) +else + $(warning WARNING: $(HOTSPOT_SERVER_PATH)/64/$(JVMDTRACE_NAME) not found!) endif # For backwards compatability, make a link of the 32-bit client JVM to $(LIBDIR) @@ -224,6 +247,18 @@ $(LIB_LOCATION)/$(SERVER_LOCATION)/$(JVMDB_NAME): $(HOTSPOT_SERVER_PATH)/$(JVMDB $(LIB_LOCATION)/$(SERVER_LOCATION)/64/$(JVMDB_NAME): $(HOTSPOT_SERVER_PATH)/64/$(JVMDB_NAME) $(install-import-file) +$(LIB_LOCATION)/$(CLIENT_LOCATION)/$(JVMDTRACE_NAME): $(HOTSPOT_CLIENT_PATH)/$(JVMDTRACE_NAME) + $(install-import-file) + +$(LIB_LOCATION)/$(CLIENT_LOCATION)/64/$(JVMDTRACE_NAME): $(HOTSPOT_CLIENT_PATH)/64/$(JVMDTRACE_NAME) + $(install-import-file) + +$(LIB_LOCATION)/$(SERVER_LOCATION)/$(JVMDTRACE_NAME): $(HOTSPOT_SERVER_PATH)/$(JVMDTRACE_NAME) + $(install-import-file) + +$(LIB_LOCATION)/$(SERVER_LOCATION)/64/$(JVMDTRACE_NAME): $(HOTSPOT_SERVER_PATH)/64/$(JVMDTRACE_NAME) + $(install-import-file) + $(LIB_LOCATION)/$(SERVER_LOCATION)/$(JVM_NAME): $(HOTSPOT_SERVER_PATH)/$(JVM_NAME) $(install-import-file) diff --git a/jdk/make/java/text/base/FILES_java.gmk b/jdk/make/java/text/base/FILES_java.gmk index 414390822c3..8d721300c27 100644 --- a/jdk/make/java/text/base/FILES_java.gmk +++ b/jdk/make/java/text/base/FILES_java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ FILES_java = \ java/text/AttributedString.java \ java/text/BreakDictionary.java \ java/text/BreakIterator.java \ + java/text/CalendarBuilder.java \ java/text/CharacterIterator.java \ java/text/CharacterIteratorFieldDelegate.java \ java/text/ChoiceFormat.java \ diff --git a/jdk/make/jdk_generic_profile.sh b/jdk/make/jdk_generic_profile.sh index 3f2e08446f0..4363a1b710e 100644 --- a/jdk/make/jdk_generic_profile.sh +++ b/jdk/make/jdk_generic_profile.sh @@ -340,6 +340,10 @@ PATH="${path4sdk}" export PATH # Export variables required for Zero +if [ "${SHARK_BUILD}" = true ] ; then + ZERO_BUILD=true + export ZERO_BUILD +fi if [ "${ZERO_BUILD}" = true ] ; then # ZERO_LIBARCH is the name of the architecture-specific # subdirectory under $JAVA_HOME/jre/lib @@ -417,4 +421,55 @@ if [ "${ZERO_BUILD}" = true ] ; then fi export LIBFFI_CFLAGS export LIBFFI_LIBS + + # LLVM_CFLAGS, LLVM_LDFLAGS and LLVM_LIBS tell the compiler how to + # compile and link against LLVM + if [ "${SHARK_BUILD}" = true ] ; then + if [ "${LLVM_CONFIG}" = "" ] ; then + LLVM_CONFIG=$(which llvm-config 2>/dev/null) + fi + if [ ! -x "${LLVM_CONFIG}" ] ; then + echo "ERROR: Unable to locate llvm-config" + exit 1 + fi + llvm_components="jit engine nativecodegen" + + unset LLVM_CFLAGS + for flag in $("${LLVM_CONFIG}" --cxxflags $llvm_components); do + if echo "${flag}" | grep -q '^-[ID]'; then + if [ "${flag}" != "-D_DEBUG" ] ; then + if [ "${LLVM_CFLAGS}" != "" ] ; then + LLVM_CFLAGS="${LLVM_CFLAGS} " + fi + LLVM_CFLAGS="${LLVM_CFLAGS}${flag}" + fi + fi + done + llvm_version=$("${LLVM_CONFIG}" --version | sed 's/\.//; s/svn.*//') + LLVM_CFLAGS="${LLVM_CFLAGS} -DSHARK_LLVM_VERSION=${llvm_version}" + + unset LLVM_LDFLAGS + for flag in $("${LLVM_CONFIG}" --ldflags $llvm_components); do + if echo "${flag}" | grep -q '^-L'; then + if [ "${LLVM_LDFLAGS}" != "" ] ; then + LLVM_LDFLAGS="${LLVM_LDFLAGS} " + fi + LLVM_LDFLAGS="${LLVM_LDFLAGS}${flag}" + fi + done + + unset LLVM_LIBS + for flag in $("${LLVM_CONFIG}" --libs $llvm_components); do + if echo "${flag}" | grep -q '^-l'; then + if [ "${LLVM_LIBS}" != "" ] ; then + LLVM_LIBS="${LLVM_LIBS} " + fi + LLVM_LIBS="${LLVM_LIBS}${flag}" + fi + done + + export LLVM_CFLAGS + export LLVM_LDFLAGS + export LLVM_LIBS + fi fi diff --git a/jdk/make/jprt.properties b/jdk/make/jprt.properties index 5a6ca7d4c2b..4ae844da4a2 100644 --- a/jdk/make/jprt.properties +++ b/jdk/make/jprt.properties @@ -24,32 +24,12 @@ # # Properties for jprt -jprt.tools.default.release=jdk1.7.0 -# Specific platform list -jprt.build.platforms=\ -solaris_sparc_5.10,\ -solaris_sparcv9_5.10,\ -solaris_i586_5.10,\ -solaris_x64_5.10,\ -linux_i586_2.6,\ -linux_x64_2.6,\ -windows_i586_5.0,\ -windows_x64_5.2 +# Use whatever release that the submitted job requests +jprt.tools.default.release=${jprt.submit.release} -# The different build flavors we want +# The different build flavors we want, we override here so we just get these 2 jprt.build.flavors=product,fastdebug -jprt.run.flavors=c1,c2 -jprt.solaris_sparcv9.run.flavors=c2 -jprt.solaris_x64.run.flavors=c2 -jprt.windows_x64.run.flavors=c2 -jprt.linux_x64.run.flavors=c2 -jprt.run.flavor.c1.option=-client -jprt.run.flavor.c2.option=-server - -# Explicitly designate what the 32bit match is for the 64bit build -jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10 -jprt.solaris_x64.build.platform.match32=solaris_i586_5.10 # Standard test target for everybody jprt.test.targets=*-*-*-jvm98 @@ -83,6 +63,6 @@ jprt2.make.rule.test.targets= \ *-product-*-jdk_rmi, \ *-product-*-jdk_swing, \ -# Directories needed to build -jprt.bundle.exclude.src.dirs=build +# Directories to be excluded from the source bundles +jprt.bundle.exclude.src.dirs=build dist webrev diff --git a/jdk/make/sun/cmm/lcms/FILES_c_unix.gmk b/jdk/make/sun/cmm/lcms/FILES_c_unix.gmk index 86676ffa826..91787becd5e 100644 --- a/jdk/make/sun/cmm/lcms/FILES_c_unix.gmk +++ b/jdk/make/sun/cmm/lcms/FILES_c_unix.gmk @@ -25,7 +25,6 @@ FILES_c = \ cmscam02.c \ - cmscam97.c \ cmscgats.c \ cmscnvrt.c \ cmserr.c \ @@ -35,13 +34,17 @@ FILES_c = \ cmsio0.c \ cmsio1.c \ cmslut.c \ - cmsmatsh.c \ + cmsmd5.c \ cmsmtrx.c \ cmsnamed.c \ + cmsopt.c \ cmspack.c \ cmspcs.c \ + cmsplugin.c \ cmsps2.c \ cmssamp.c \ + cmssm.c \ + cmstypes.c \ cmsvirt.c \ cmswtpnt.c \ cmsxform.c \ diff --git a/jdk/make/sun/cmm/lcms/FILES_c_windows.gmk b/jdk/make/sun/cmm/lcms/FILES_c_windows.gmk index 86676ffa826..91787becd5e 100644 --- a/jdk/make/sun/cmm/lcms/FILES_c_windows.gmk +++ b/jdk/make/sun/cmm/lcms/FILES_c_windows.gmk @@ -25,7 +25,6 @@ FILES_c = \ cmscam02.c \ - cmscam97.c \ cmscgats.c \ cmscnvrt.c \ cmserr.c \ @@ -35,13 +34,17 @@ FILES_c = \ cmsio0.c \ cmsio1.c \ cmslut.c \ - cmsmatsh.c \ + cmsmd5.c \ cmsmtrx.c \ cmsnamed.c \ + cmsopt.c \ cmspack.c \ cmspcs.c \ + cmsplugin.c \ cmsps2.c \ cmssamp.c \ + cmssm.c \ + cmstypes.c \ cmsvirt.c \ cmswtpnt.c \ cmsxform.c \ diff --git a/jdk/make/sun/cmm/lcms/Makefile b/jdk/make/sun/cmm/lcms/Makefile index 5f7ca42e4e3..1072c2fac7b 100644 --- a/jdk/make/sun/cmm/lcms/Makefile +++ b/jdk/make/sun/cmm/lcms/Makefile @@ -80,8 +80,8 @@ vpath %.c $(SHARE_SRC)/native/$(PKGDIR) vpath %.c $(SHARE_SRC)/native/sun/java2d ifeq ($(PLATFORM), windows) - -OTHER_LDLIBS = user32.lib version.lib $(OBJDIR)/../../../sun.awt/awt/$(OBJDIRNAME)/awt.lib +OTHER_CFLAGS += -DCMS_IS_WINDOWS_ -Dsqrtf=sqrt +OTHER_LDLIBS = $(OBJDIR)/../../../sun.awt/awt/$(OBJDIRNAME)/awt.lib OTHER_INCLUDES += -I$(SHARE_SRC)/native/sun/java2d \ -I$(SHARE_SRC)/native/sun/awt/debug diff --git a/jdk/make/sun/javazic/tzdata/VERSION b/jdk/make/sun/javazic/tzdata/VERSION index e3847595a31..804986c10b7 100644 --- a/jdk/make/sun/javazic/tzdata/VERSION +++ b/jdk/make/sun/javazic/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2010i +tzdata2010l diff --git a/jdk/make/sun/javazic/tzdata/africa b/jdk/make/sun/javazic/tzdata/africa index c0bdbe92e7e..ce560077e00 100644 --- a/jdk/make/sun/javazic/tzdata/africa +++ b/jdk/make/sun/javazic/tzdata/africa @@ -316,8 +316,25 @@ Rule Egypt 2007 only - Sep Thu>=1 23:00s 0 - # and can be found by searching for "winter" in their search engine # (at least today). +# From Alexander Krivenyshev (2010-07-20): +# According to News from Egypt - Al-Masry Al-Youm Egypt's cabinet has +# decided that Daylight Saving Time will not be used in Egypt during +# Ramadan. +# +# Arabic translation: +# "Clocks to go back during Ramadan--and then forward again" +# +# http://www.almasryalyoum.com/en/news/clocks-go-back-during-ramadan-and-then-forward-again +# +# or +# +# http://www.worldtimezone.com/dst_news/dst_news_egypt02.html +# + Rule Egypt 2008 only - Aug lastThu 23:00s 0 - Rule Egypt 2009 only - Aug 20 23:00s 0 - +Rule Egypt 2010 only - Aug 11 0:00 0 - +Rule Egypt 2010 only - Sep 10 0:00 1:00 S Rule Egypt 2010 max - Sep lastThu 23:00s 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] diff --git a/jdk/make/sun/javazic/tzdata/asia b/jdk/make/sun/javazic/tzdata/asia index d4b6cc3c1d2..bc69266fa95 100644 --- a/jdk/make/sun/javazic/tzdata/asia +++ b/jdk/make/sun/javazic/tzdata/asia @@ -2200,6 +2200,18 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # "At 12:01am Friday, clocks in Israel and the West Bank will change to # 1:01am, while Gaza clocks will change at 12:01am Saturday morning." +# From Steffen Thorsen (2010-08-11): +# According to several sources, including +# +# http://www.maannews.net/eng/ViewDetails.aspx?ID=306795 +# +# the clocks were set back one hour at 2010-08-11 00:00:00 local time in +# Gaza and the West Bank. +# Some more background info: +# +# http://www.timeanddate.com/news/time/westbank-gaza-end-dst-2010.html +# + # The rules for Egypt are stolen from the `africa' file. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule EgyptAsia 1957 only - May 10 0:00 1:00 S @@ -2220,6 +2232,7 @@ Rule Palestine 2008 only - Aug lastFri 2:00 0 - Rule Palestine 2009 only - Mar lastFri 0:00 1:00 S Rule Palestine 2010 max - Mar lastSat 0:01 1:00 S Rule Palestine 2009 max - Sep Fri>=1 2:00 0 - +Rule Palestine 2010 only - Aug 11 0:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct diff --git a/jdk/make/sun/javazic/tzdata/australasia b/jdk/make/sun/javazic/tzdata/australasia index f66d663986a..b406c592761 100644 --- a/jdk/make/sun/javazic/tzdata/australasia +++ b/jdk/make/sun/javazic/tzdata/australasia @@ -368,10 +368,10 @@ Zone Pacific/Kwajalein 11:09:20 - LMT 1901 # Micronesia # Zone NAME GMTOFF RULES FORMAT [UNTIL] -Zone Pacific/Truk 10:07:08 - LMT 1901 - 10:00 - TRUT # Truk Time -Zone Pacific/Ponape 10:32:52 - LMT 1901 # Kolonia - 11:00 - PONT # Ponape Time +Zone Pacific/Chuuk 10:07:08 - LMT 1901 + 10:00 - CHUT # Chuuk Time +Zone Pacific/Pohnpei 10:32:52 - LMT 1901 # Kolonia + 11:00 - PONT # Pohnpei Time Zone Pacific/Kosrae 10:51:56 - LMT 1901 11:00 - KOST 1969 Oct # Kosrae Time 12:00 - KOST 1999 diff --git a/jdk/make/sun/javazic/tzdata/backward b/jdk/make/sun/javazic/tzdata/backward index 1116af03170..4ccea7c7dbe 100644 --- a/jdk/make/sun/javazic/tzdata/backward +++ b/jdk/make/sun/javazic/tzdata/backward @@ -112,7 +112,9 @@ Link Pacific/Chatham NZ-CHAT Link America/Denver Navajo Link Asia/Shanghai PRC Link Pacific/Pago_Pago Pacific/Samoa -Link Pacific/Truk Pacific/Yap +Link Pacific/Chuuk Pacific/Yap +Link Pacific/Chuuk Pacific/Truk +Link Pacific/Pohnpei Pacific/Ponape Link Europe/Warsaw Poland Link Europe/Lisbon Portugal Link Asia/Taipei ROC diff --git a/jdk/make/sun/javazic/tzdata/europe b/jdk/make/sun/javazic/tzdata/europe index d806f6ef000..6fc7d22f3c2 100644 --- a/jdk/make/sun/javazic/tzdata/europe +++ b/jdk/make/sun/javazic/tzdata/europe @@ -1035,22 +1035,47 @@ Zone Europe/Tallinn 1:39:00 - LMT 1880 2:00 EU EE%sT # Finland -# + # From Hannu Strang (1994-09-25 06:03:37 UTC): # Well, here in Helsinki we're just changing from summer time to regular one, # and it's supposed to change at 4am... + +# From Janne Snabb (2010-0715): # -# From Paul Eggert (2006-03-22): -# Shanks & Pottenger say Finland has switched at 02:00 standard time -# since 1981. Go with Strang instead. +# I noticed that the Finland data is not accurate for years 1981 and 1982. +# During these two first trial years the DST adjustment was made one hour +# earlier than in forthcoming years. Starting 1983 the adjustment was made +# according to the central European standards. # +# This is documented in Heikki Oja: Aikakirja 2007, published by The Almanac +# Office of University of Helsinki, ISBN 952-10-3221-9, available online (in +# Finnish) at +# +# +# http://almanakka.helsinki.fi/aikakirja/Aikakirja2007kokonaan.pdf +# +# +# Page 105 (56 in PDF version) has a handy table of all past daylight savings +# transitions. It is easy enough to interpret without Finnish skills. +# +# This is also confirmed by Finnish Broadcasting Company's archive at: +# +# +# http://www.yle.fi/elavaarkisto/?s=s&g=1&ag=5&t=&a=3401 +# +# +# The news clip from 1981 says that "the time between 2 and 3 o'clock does not +# exist tonight." + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Finland 1942 only - Apr 3 0:00 1:00 S Rule Finland 1942 only - Oct 3 0:00 0 - +Rule Finland 1981 1982 - Mar lastSun 2:00 1:00 S +Rule Finland 1981 1982 - Sep lastSun 3:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Europe/Helsinki 1:39:52 - LMT 1878 May 31 1:39:52 - HMT 1921 May # Helsinki Mean Time - 2:00 Finland EE%sT 1981 Mar 29 2:00 + 2:00 Finland EE%sT 1983 2:00 EU EE%sT # Aaland Is diff --git a/jdk/make/sun/javazic/tzdata/leapseconds b/jdk/make/sun/javazic/tzdata/leapseconds index f674e22c18c..50426088b76 100644 --- a/jdk/make/sun/javazic/tzdata/leapseconds +++ b/jdk/make/sun/javazic/tzdata/leapseconds @@ -82,9 +82,9 @@ Leap 2008 Dec 31 23:59:60 + S # FAX : 33 (0) 1 40 51 22 91 # Internet : services.iers@obspm.fr # -# Paris, 4 July 2009 +# Paris, 14 July 2010 # -# Bulletin C 38 +# Bulletin C 40 # # To authorities responsible # for the measurement and @@ -92,9 +92,9 @@ Leap 2008 Dec 31 23:59:60 + S # # INFORMATION ON UTC - TAI # -# NO positive leap second will be introduced at the end of December 2009. +# NO positive leap second will be introduced at the end of December 2010. # The difference between Coordinated Universal Time UTC and the -# International Atomic Time TAI is : +# International Atomic Time TAI is : # # from 2009 January 1, 0h UTC, until further notice : UTC-TAI = -34 s # @@ -104,6 +104,6 @@ Leap 2008 Dec 31 23:59:60 + S # will be no time step at the next possible date. # # Daniel GAMBIS -# Director +# Director # Earth Orientation Center of IERS # Observatoire de Paris, France diff --git a/jdk/make/sun/javazic/tzdata/northamerica b/jdk/make/sun/javazic/tzdata/northamerica index ed833a1e358..d07c69c9b45 100644 --- a/jdk/make/sun/javazic/tzdata/northamerica +++ b/jdk/make/sun/javazic/tzdata/northamerica @@ -1346,6 +1346,83 @@ Zone America/Montreal -4:54:16 - LMT 1884 # entry since our cutoff date of 1970, so we can move # America/Coral_Harbour to the 'backward' file. +# From Mark Brader (2010-03-06): +# +# Currently the database has: +# +# # Ontario +# +# # From Paul Eggert (2006-07-09): +# # Shanks & Pottenger write that since 1970 most of Ontario has been like +# # Toronto. +# # Thunder Bay skipped DST in 1973. +# # Many smaller locales did not observe peacetime DST until 1974; +# # Nipigon (EST) and Rainy River (CST) are the largest that we know of. +# +# In the (Toronto) Globe and Mail for Saturday, 1955-09-24, in the bottom +# right corner of page 1, it says that Toronto will return to standard +# time at 2 am Sunday morning (which agrees with the database), and that: +# +# The one-hour setback will go into effect throughout most of Ontario, +# except in areas like Windsor which remains on standard time all year. +# +# Windsor is, of course, a lot larger than Nipigon. +# +# I only came across this incidentally. I don't know if Windsor began +# observing DST when Detroit did, or in 1974, or on some other date. +# +# By the way, the article continues by noting that: +# +# Some cities in the United States have pushed the deadline back +# three weeks and will change over from daylight saving in October. + +# From Arthur David Olson (2010-07-17): +# +# "Standard Time and Time Zones in Canada" appeared in +# The Journal of The Royal Astronomical Society of Canada, +# volume 26, number 2 (February 1932) and, as of 2010-07-17, +# was available at +# +# http://adsabs.harvard.edu/full/1932JRASC..26...49S +# +# +# It includes the text below (starting on page 57): +# +# A list of the places in Canada using daylight saving time would +# require yearly revision. From information kindly furnished by +# the provincial governments and by the postmasters in many cities +# and towns, it is found that the following places used daylight sav- +# ing in 1930. The information for the province of Quebec is definite, +# for the other provinces only approximate: +# +# Province Daylight saving time used +# Prince Edward Island Not used. +# Nova Scotia In Halifax only. +# New Brunswick In St. John only. +# Quebec In the following places: +# Montreal Lachine +# Quebec Mont-Royal +# Levis Iberville +# St. Lambert Cap de la Madeleine +# Verdun Loretteville +# Westmount Richmond +# Outremont St. Jerome +# Longueuil Greenfield Park +# Arvida Waterloo +# Chambly-Canton Beaulieu +# Melbourne La Tuque +# St. Theophile Buckingham +# Ontario Used generally in the cities and towns along +# the southerly part of the province. Not +# used in the northwesterlhy part. +# Manitoba Not used. +# Saskatchewan In Regina only. +# Alberta Not used. +# British Columbia Not used. +# +# With some exceptions, the use of daylight saving may be said to be limited +# to those cities and towns lying between Quebec city and Windsor, Ont. + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Toronto 1919 only - Mar 30 23:30 1:00 D Rule Toronto 1919 only - Oct 26 0:00 0 S @@ -2111,7 +2188,44 @@ Zone America/Hermosillo -7:23:52 - LMT 1921 Dec 31 23:36:08 -8:00 - PST 1970 -7:00 Mexico M%sT 1999 -7:00 - MST + +# From Alexander Krivenyshev (2010-04-21): +# According to news, Bahía de Banderas (Mexican state of Nayarit) +# changed time zone UTC-7 to new time zone UTC-6 on April 4, 2010 (to +# share the same time zone as nearby city Puerto Vallarta, Jalisco). +# +# (Spanish) +# Bahía de Banderas homologa su horario al del centro del +# país, a partir de este domingo +# +# http://www.nayarit.gob.mx/notes.asp?id=20748 +# +# +# Bahía de Banderas homologa su horario con el del Centro del +# País +# +# http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50" +# +# +# (English) +# Puerto Vallarta and Bahía de Banderas: One Time Zone +# +# http://virtualvallarta.com/puertovallarta/puertovallarta/localnews/2009-12-03-Puerto-Vallarta-and-Bahia-de-Banderas-One-Time-Zone.shtml +# +# +# or +# +# http://www.worldtimezone.com/dst_news/dst_news_mexico08.html +# +# +# "Mexico's Senate approved the amendments to the Mexican Schedule System that +# will allow Bahía de Banderas and Puerto Vallarta to share the same time +# zone ..." # Baja California Sur, Nayarit, Sinaloa + +# From Arthur David Olson (2010-05-01): +# Use "Bahia_Banderas" to keep the name to fourteen characters. + Zone America/Mazatlan -7:05:40 - LMT 1921 Dec 31 23:54:20 -7:00 - MST 1927 Jun 10 23:00 -6:00 - CST 1930 Nov 15 @@ -2122,6 +2236,19 @@ Zone America/Mazatlan -7:05:40 - LMT 1921 Dec 31 23:54:20 -7:00 - MST 1949 Jan 14 -8:00 - PST 1970 -7:00 Mexico M%sT + +Zone America/Bahia_Banderas -7:01:00 - LMT 1921 Dec 31 23:59:00 + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 + -7:00 - MST 1931 May 1 23:00 + -6:00 - CST 1931 Oct + -7:00 - MST 1932 Apr 1 + -6:00 - CST 1942 Apr 24 + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1970 + -7:00 Mexico M%sT 2010 Apr 4 2:00 + -6:00 Mexico C%sT + # Baja California (near US border) Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 0:11:56 -7:00 - MST 1924 diff --git a/jdk/make/sun/javazic/tzdata/zone.tab b/jdk/make/sun/javazic/tzdata/zone.tab index 0d5feba865b..b63bd11ffc4 100644 --- a/jdk/make/sun/javazic/tzdata/zone.tab +++ b/jdk/make/sun/javazic/tzdata/zone.tab @@ -199,8 +199,8 @@ ET +0902+03842 Africa/Addis_Ababa FI +6010+02458 Europe/Helsinki FJ -1808+17825 Pacific/Fiji FK -5142-05751 Atlantic/Stanley -FM +0725+15147 Pacific/Truk Truk (Chuuk) and Yap -FM +0658+15813 Pacific/Ponape Ponape (Pohnpei) +FM +0725+15147 Pacific/Chuuk Chuuk (Truk) and Yap +FM +0658+15813 Pacific/Pohnpei Pohnpei (Ponape) FM +0519+16259 Pacific/Kosrae Kosrae FO +6201-00646 Atlantic/Faroe FR +4852+00220 Europe/Paris @@ -310,6 +310,7 @@ MX +2934-10425 America/Ojinaga US Mountain Time - Chihuahua near US border MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora MX +3232-11701 America/Tijuana US Pacific Time - Baja California near US border MX +3018-11452 America/Santa_Isabel Mexican Pacific Time - Baja California away from US border +MX +2048-10515 America/Bahia_Banderas Mexican Central Time - Bahia de Banderas MY +0310+10142 Asia/Kuala_Lumpur peninsular Malaysia MY +0133+11020 Asia/Kuching Sabah & Sarawak MZ -2558+03235 Africa/Maputo diff --git a/jdk/make/sun/net/FILES_java.gmk b/jdk/make/sun/net/FILES_java.gmk index 3eba9b01a17..1fcec35f4e4 100644 --- a/jdk/make/sun/net/FILES_java.gmk +++ b/jdk/make/sun/net/FILES_java.gmk @@ -53,6 +53,7 @@ FILES_java = \ sun/net/ftp/FtpProtocolException.java \ sun/net/ftp/impl/FtpClient.java \ sun/net/ftp/impl/DefaultFtpClientProvider.java \ + sun/net/sdp/SdpSupport.java \ sun/net/spi/DefaultProxySelector.java \ sun/net/spi/nameservice/NameServiceDescriptor.java \ sun/net/spi/nameservice/NameService.java \ @@ -136,8 +137,6 @@ FILES_java = \ ifeq ($(PLATFORM), windows) FILES_java += sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java -endif - -ifeq ($(PLATFORM), solaris) - FILES_java += sun/net/spi/SdpProvider.java +else + FILES_java += sun/net/sdp/SdpProvider.java endif diff --git a/jdk/make/templates/gpl-cp-header b/jdk/make/templates/gpl-cp-header index 59473be222a..ed422f45fdc 100644 --- a/jdk/make/templates/gpl-cp-header +++ b/jdk/make/templates/gpl-cp-header @@ -17,6 +17,6 @@ You should have received a copy of the GNU General Public License version 2 along with this work; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -CA 95054 USA or visit www.sun.com if you need additional information or -have any questions. +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. diff --git a/jdk/make/templates/gpl-header b/jdk/make/templates/gpl-header index 07dbc05ecb7..e717b45b516 100644 --- a/jdk/make/templates/gpl-header +++ b/jdk/make/templates/gpl-header @@ -15,6 +15,6 @@ You should have received a copy of the GNU General Public License version 2 along with this work; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -CA 95054 USA or visit www.sun.com if you need additional information or -have any questions. +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. diff --git a/jdk/src/share/bin/java.c b/jdk/src/share/bin/java.c index 6f24932e550..4c61fb7c853 100644 --- a/jdk/src/share/bin/java.c +++ b/jdk/src/share/bin/java.c @@ -712,19 +712,19 @@ SetModulesBootClassPath(const char *jrepath) struct stat statbuf; /* return if jre/lib/rt.jar exists */ - sprintf(pathname, "%s%slib%srt.jar", jrepath, separator, separator); + JLI_Snprintf(pathname, sizeof(pathname), "%s%slib%srt.jar", jrepath, separator, separator); if (stat(pathname, &statbuf) == 0) { return; } /* return if jre/classes exists */ - sprintf(pathname, "%s%sclasses", jrepath, separator); + JLI_Snprintf(pathname, sizeof(pathname), "%s%sclasses", jrepath, separator); if (stat(pathname, &statbuf) == 0) { return; } /* modularized jre */ - sprintf(pathname, "%s%slib%s*", jrepath, separator, separator); + JLI_Snprintf(pathname, sizeof(pathname), "%s%slib%s*", jrepath, separator, separator); s = (char *) JLI_WildcardExpandClasspath(pathname); def = JLI_MemAlloc(sizeof(format) - 2 /* strlen("%s") */ @@ -1624,11 +1624,8 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) if (JLI_IsTraceLauncher()) { start = CounterGet(); } - - JLI_StrCpy(jvmCfgName, jrepath); - JLI_StrCat(jvmCfgName, FILESEP "lib" FILESEP); - JLI_StrCat(jvmCfgName, arch); - JLI_StrCat(jvmCfgName, FILESEP "jvm.cfg"); + JLI_Snprintf(jvmCfgName, sizeof(jvmCfgName), "%s%slib%s%s%sjvm.cfg", + jrepath, FILESEP, FILESEP, arch, FILESEP); jvmCfg = fopen(jvmCfgName, "r"); if (jvmCfg == NULL) { diff --git a/jdk/src/share/classes/com/oracle/net/Sdp.java b/jdk/src/share/classes/com/oracle/net/Sdp.java new file mode 100644 index 00000000000..32316073828 --- /dev/null +++ b/jdk/src/share/classes/com/oracle/net/Sdp.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.net; + +import java.net.Socket; +import java.net.ServerSocket; +import java.net.SocketImpl; +import java.net.SocketImplFactory; +import java.net.SocketException; +import java.nio.channels.SocketChannel; +import java.nio.channels.ServerSocketChannel; +import java.io.IOException; +import java.io.FileDescriptor; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.lang.reflect.Constructor; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.InvocationTargetException; + +import sun.net.sdp.SdpSupport; + +/** + * This class consists exclusively of static methods that Sockets or Channels to + * sockets that support the InfiniBand Sockets Direct Protocol (SDP). + */ + +public final class Sdp { + private Sdp() { } + + /** + * The package-privage ServerSocket(SocketImpl) constructor + */ + private static final Constructor serverSocketCtor; + static { + try { + serverSocketCtor = (Constructor) + ServerSocket.class.getDeclaredConstructor(SocketImpl.class); + setAccessible(serverSocketCtor); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + /** + * The package-private SdpSocketImpl() constructor + */ + private static final Constructor socketImplCtor; + static { + try { + Class cl = Class.forName("java.net.SdpSocketImpl", true, null); + socketImplCtor = (Constructor)cl.getDeclaredConstructor(); + setAccessible(socketImplCtor); + } catch (ClassNotFoundException e) { + throw new AssertionError(e); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + private static void setAccessible(final AccessibleObject o) { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + o.setAccessible(true); + return null; + } + }); + } + + /** + * SDP enabled Socket. + */ + private static class SdpSocket extends Socket { + SdpSocket(SocketImpl impl) throws SocketException { + super(impl); + } + } + + /** + * Creates a SDP enabled SocketImpl + */ + private static SocketImpl createSocketImpl() { + try { + return socketImplCtor.newInstance(); + } catch (InstantiationException x) { + throw new AssertionError(x); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + throw new AssertionError(x); + } + } + + /** + * Creates an unconnected and unbound SDP socket. The {@code Socket} is + * associated with a {@link java.net.SocketImpl} of the system-default type. + * + * @return a new Socket + * + * @throws UnsupportedOperationException + * If SDP is not supported + * @throws IOException + * If an I/O error occurs + */ + public static Socket openSocket() throws IOException { + SocketImpl impl = createSocketImpl(); + return new SdpSocket(impl); + } + + /** + * Creates an unbound SDP server socket. The {@code ServerSocket} is + * associated with a {@link java.net.SocketImpl} of the system-default type. + * + * @return a new ServerSocket + * + * @throws UnsupportedOperationException + * If SDP is not supported + * @throws IOException + * If an I/O error occurs + */ + public static ServerSocket openServerSocket() throws IOException { + // create ServerSocket via package-private constructor + SocketImpl impl = createSocketImpl(); + try { + return serverSocketCtor.newInstance(impl); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InstantiationException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw (IOException)cause; + if (cause instanceof RuntimeException) + throw (RuntimeException)cause; + throw new RuntimeException(x); + } + } + + /** + * Opens a socket channel to a SDP socket. + * + *

The channel will be associated with the system-wide default + * {@link java.nio.channels.spi.SelectorProvider SelectorProvider}. + * + * @return a new SocketChannel + * + * @throws UnsupportedOperationException + * If SDP is not supported or not supported by the default selector + * provider + * @throws IOException + * If an I/O error occurs. + */ + public static SocketChannel openSocketChannel() throws IOException { + FileDescriptor fd = SdpSupport.createSocket(); + return sun.nio.ch.Secrets.newSocketChannel(fd); + } + + /** + * Opens a socket channel to a SDP socket. + * + *

The channel will be associated with the system-wide default + * {@link java.nio.channels.spi.SelectorProvider SelectorProvider}. + * + * @return a new ServerSocketChannel + * + * @throws UnsupportedOperationException + * If SDP is not supported or not supported by the default selector + * provider + * @throws IOException + * If an I/O error occurs + */ + public static ServerSocketChannel openServerSocketChannel() + throws IOException + { + FileDescriptor fd = SdpSupport.createSocket(); + return sun.nio.ch.Secrets.newServerSocketChannel(fd); + } +} diff --git a/jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java b/jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java index fb2700f70b7..1ca240dd743 100644 --- a/jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java +++ b/jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,13 +31,14 @@ import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.Callable; +import java.applet.Applet; import java.awt.AWTEvent; import java.awt.EventQueue; import java.awt.Component; import java.awt.Container; +import java.awt.Window; import javax.swing.JComponent; import javax.swing.RepaintManager; -import javax.swing.SwingUtilities; /** * A collection of utility methods for Swing. @@ -91,7 +92,7 @@ public class SwingUtilities3 { */ public static void setVsyncRequested(Container rootContainer, boolean isRequested) { - assert SwingUtilities.getRoot(rootContainer) == rootContainer; + assert (rootContainer instanceof Applet) || (rootContainer instanceof Window); if (isRequested) { vsyncedMap.put(rootContainer, Boolean.TRUE); } else { @@ -106,7 +107,7 @@ public class SwingUtilities3 { * @return {@code true} if vsync painting is requested for {@code rootContainer} */ public static boolean isVsyncRequested(Container rootContainer) { - assert SwingUtilities.getRoot(rootContainer) == rootContainer; + assert (rootContainer instanceof Applet) || (rootContainer instanceof Window); return Boolean.TRUE == vsyncedMap.get(rootContainer); } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java index fa9a5a2fb15..57a816932b0 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -399,7 +399,7 @@ class GTKPainter extends SynthPainter { } String detail = "arrow"; - if (name == "ScrollBar.button") { + if ((name == "ScrollBar.button") || (name == "TabbedPane.button")) { if (arrowType == ArrowType.UP || arrowType == ArrowType.DOWN) { detail = "vscrollbar"; } else { @@ -409,7 +409,7 @@ class GTKPainter extends SynthPainter { name == "Spinner.previousButton") { detail = "spinbutton"; } else if (name != "ComboBox.arrowButton") { - assert false; + assert false : "unexpected name: " + name; } int gtkState = GTKLookAndFeel.synthStateToGTKState( @@ -436,7 +436,7 @@ class GTKPainter extends SynthPainter { String name = button.getName(); String detail = "button"; int direction = SwingConstants.CENTER; - if (name == "ScrollBar.button") { + if ((name == "ScrollBar.button") || (name == "TabbedPane.button")) { Integer prop = (Integer) button.getClientProperty("__arrow_direction__"); direction = (prop != null) ? @@ -457,7 +457,7 @@ class GTKPainter extends SynthPainter { } else if (name == "Spinner.nextButton") { detail = "spinbutton_up"; } else if (name != "ComboBox.arrowButton") { - assert false; + assert false : "unexpected name: " + name; } int state = context.getComponentState(); diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/PangoFonts.java b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/PangoFonts.java index 0c76686ebc9..1a60d277757 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/PangoFonts.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/PangoFonts.java @@ -150,11 +150,6 @@ class PangoFonts { * case for it to be a problem the values would have to be different. * It also seems unlikely to arise except when a user explicitly * deletes the X resource database entry. - * 3) Because of rounding errors sizes may differ very slightly - * between JDK and GTK. To fix that would at the very least require - * Swing to specify floating pt font sizes. - * Eg "10 pts" for GTK at 96 dpi to get the same size at Java 2D's - * 72 dpi you'd need to specify exactly 13.33. * There also some other issues to be aware of for the future: * GTK specifies the Xft.dpi value as server-wide which when used * on systems with 2 distinct X screens with different physical DPI @@ -197,11 +192,16 @@ class PangoFonts { String fcFamilyLC = family.toLowerCase(); if (FontUtilities.mapFcName(fcFamilyLC) != null) { /* family is a Fc/Pango logical font which we need to expand. */ - return FontUtilities.getFontConfigFUIR(fcFamilyLC, style, size); + Font font = FontUtilities.getFontConfigFUIR(fcFamilyLC, style, size); + font = font.deriveFont(style, (float)dsize); + return new FontUIResource(font); } else { /* It's a physical font which we will create with a fallback */ - Font font = new FontUIResource(family, style, size); - return FontUtilities.getCompositeFontUIResource(font); + Font font = new Font(family, style, size); + /* a roundabout way to set the font size in floating points */ + font = font.deriveFont(style, (float)dsize); + FontUIResource fuir = new FontUIResource(font); + return FontUtilities.getCompositeFontUIResource(fuir); } } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java index cd68cca1bdf..4b140f17f89 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,8 +40,6 @@ import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; -import java.io.Serializable; - /** * Factory object that can vend Icons appropriate for the basic L & F. *

@@ -99,7 +97,7 @@ public class MotifBorders { } public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { - if (((JComponent)c).hasFocus()) { + if (c.hasFocus()) { g.setColor(focus); g.drawRect(x, y, w-1, h-1); } else { @@ -233,6 +231,9 @@ public class MotifBorders { } public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + if (!(c instanceof JMenuBar)) { + return; + } JMenuBar menuBar = (JMenuBar)c; if (menuBar.isBorderPainted() == true) { // this draws the MenuBar border @@ -658,6 +659,9 @@ public class MotifBorders { * @param height the height of the painted border */ public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + if (!(c instanceof JPopupMenu)) { + return; + } Font origFont = g.getFont(); Color origColor = g.getColor(); @@ -701,6 +705,9 @@ public class MotifBorders { * @param insets the object to be reinitialized */ public Insets getBorderInsets(Component c, Insets insets) { + if (!(c instanceof JPopupMenu)) { + return insets; + } FontMetrics fm; int descent = 0; int ascent = 16; diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java index 537618c6b01..286c3a516bd 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,12 +32,8 @@ import javax.swing.plaf.basic.*; import java.awt.Component; import java.awt.Insets; -import java.awt.Dimension; -import java.awt.Image; -import java.awt.Rectangle; import java.awt.Color; import java.awt.Graphics; -import java.io.Serializable; import static com.sun.java.swing.plaf.windows.TMSchema.*; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; @@ -159,6 +155,9 @@ public class WindowsBorders { public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + if (!(c instanceof JToolBar)) { + return; + } g.translate(x, y); XPStyle xp = XPStyle.getXP(); @@ -190,33 +189,33 @@ public class WindowsBorders { } else { - if (!vertical) { - if (c.getComponentOrientation().isLeftToRight()) { + if (!vertical) { + if (c.getComponentOrientation().isLeftToRight()) { + g.setColor(shadow); + g.drawLine(4, 3, 4, height - 4); + g.drawLine(4, height - 4, 2, height - 4); + + g.setColor(highlight); + g.drawLine(2, 3, 3, 3); + g.drawLine(2, 3, 2, height - 5); + } else { + g.setColor(shadow); + g.drawLine(width - 3, 3, width - 3, height - 4); + g.drawLine(width - 4, height - 4, width - 4, height - 4); + + g.setColor(highlight); + g.drawLine(width - 5, 3, width - 4, 3); + g.drawLine(width - 5, 3, width - 5, height - 5); + } + } else { // Vertical g.setColor(shadow); - g.drawLine(4, 3, 4, height - 4); - g.drawLine(4, height - 4, 2, height - 4); + g.drawLine(3, 4, width - 4, 4); + g.drawLine(width - 4, 2, width - 4, 4); g.setColor(highlight); - g.drawLine(2, 3, 3, 3); - g.drawLine(2, 3, 2, height - 5); - } else { - g.setColor(shadow); - g.drawLine(width - 3, 3, width - 3, height - 4); - g.drawLine(width - 4, height - 4, width - 4, height - 4); - - g.setColor(highlight); - g.drawLine(width - 5, 3, width - 4, 3); - g.drawLine(width - 5, 3, width - 5, height - 5); + g.drawLine(3, 2, width - 4, 2); + g.drawLine(3, 2, 3, 3); } - } else { // Vertical - g.setColor(shadow); - g.drawLine(3, 4, width - 4, 4); - g.drawLine(width - 4, 2, width - 4, 4); - - g.setColor(highlight); - g.drawLine(3, 2, width - 4, 2); - g.drawLine(3, 2, 3, 3); - } } } @@ -225,6 +224,9 @@ public class WindowsBorders { public Insets getBorderInsets(Component c, Insets insets) { insets.set(1,1,1,1); + if (!(c instanceof JToolBar)) { + return insets; + } if (((JToolBar)c).isFloatable()) { int gripInset = (XPStyle.getXP() != null) ? 12 : 9; if (((JToolBar)c).getOrientation() == HORIZONTAL) { diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java index 515218729ed..0c1b0954300 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ package com.sun.java.util.jar.pack; import java.io.*; import java.util.*; -import com.sun.java.util.jar.pack.Package.Class; import com.sun.java.util.jar.pack.ConstantPool.*; /** @@ -96,20 +95,20 @@ class Attribute implements Comparable, Constants { return this.def.compareTo(that.def); } - static private final byte[] noBytes = {}; - static private final HashMap canonLists = new HashMap(); - static private final HashMap attributes = new HashMap(); - static private final HashMap standardDefs = new HashMap(); + private static final byte[] noBytes = {}; + private static final Map, List> canonLists = new HashMap<>(); + private static final Map attributes = new HashMap<>(); + private static final Map standardDefs = new HashMap<>(); // Canonicalized lists of trivial attrs (Deprecated, etc.) // are used by trimToSize, in order to reduce footprint // of some common cases. (Note that Code attributes are // always zero size.) - public static List getCanonList(List al) { + public static List getCanonList(List al) { synchronized (canonLists) { - List cl = (List) canonLists.get(al); + List cl = canonLists.get(al); if (cl == null) { - cl = new ArrayList(al.size()); + cl = new ArrayList<>(al.size()); cl.addAll(al); cl = Collections.unmodifiableList(cl); canonLists.put(al, cl); @@ -122,7 +121,7 @@ class Attribute implements Comparable, Constants { public static Attribute find(int ctype, String name, String layout) { Layout key = Layout.makeKey(ctype, name, layout); synchronized (attributes) { - Attribute a = (Attribute) attributes.get(key); + Attribute a = attributes.get(key); if (a == null) { a = new Layout(ctype, name, layout).canonicalInstance(); attributes.put(key, a); @@ -131,24 +130,29 @@ class Attribute implements Comparable, Constants { } } - public static Object keyForLookup(int ctype, String name) { + public static Layout keyForLookup(int ctype, String name) { return Layout.makeKey(ctype, name); } // Find canonical empty attribute with given ctype and name, // and with the standard layout. - public static Attribute lookup(Map defs, int ctype, String name) { - if (defs == null) defs = standardDefs; - return (Attribute) defs.get(Layout.makeKey(ctype, name)); + public static Attribute lookup(Map defs, int ctype, + String name) { + if (defs == null) { + defs = standardDefs; + } + return defs.get(Layout.makeKey(ctype, name)); } - public static Attribute define(Map defs, int ctype, String name, String layout) { + + public static Attribute define(Map defs, int ctype, + String name, String layout) { Attribute a = find(ctype, name, layout); defs.put(Layout.makeKey(ctype, name), a); return a; } static { - Map sd = standardDefs; + Map sd = standardDefs; define(sd, ATTR_CONTEXT_CLASS, "Signature", "RSH"); define(sd, ATTR_CONTEXT_CLASS, "Synthetic", ""); define(sd, ATTR_CONTEXT_CLASS, "Deprecated", ""); @@ -244,7 +248,7 @@ class Attribute implements Comparable, Constants { +"\n ()[] ]" ) }; - Map sd = standardDefs; + Map sd = standardDefs; String defaultLayout = mdLayouts[2]; String annotationsLayout = mdLayouts[1] + mdLayouts[2]; String paramsLayout = mdLayouts[0] + annotationsLayout; @@ -275,10 +279,6 @@ class Attribute implements Comparable, Constants { return null; } - public static Map getStandardDefs() { - return new HashMap(standardDefs); - } - /** Base class for any attributed object (Class, Field, Method, Code). * Flags are included because they are used to help transmit the * presence of attributes. That is, flags are a mix of modifier @@ -291,7 +291,7 @@ class Attribute implements Comparable, Constants { protected abstract Entry[] getCPMap(); protected int flags; // defined here for convenience - protected List attributes; + protected List attributes; public int attributeSize() { return (attributes == null) ? 0 : attributes.size(); @@ -301,16 +301,15 @@ class Attribute implements Comparable, Constants { if (attributes == null) { return; } - if (attributes.size() == 0) { + if (attributes.isEmpty()) { attributes = null; return; } if (attributes instanceof ArrayList) { - ArrayList al = (ArrayList) attributes; + ArrayList al = (ArrayList)attributes; al.trimToSize(); boolean allCanon = true; - for (Iterator i = al.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : al) { if (!a.isCanonical()) { allCanon = false; } @@ -330,9 +329,9 @@ class Attribute implements Comparable, Constants { public void addAttribute(Attribute a) { if (attributes == null) - attributes = new ArrayList(3); + attributes = new ArrayList<>(3); else if (!(attributes instanceof ArrayList)) - attributes = new ArrayList(attributes); // unfreeze it + attributes = new ArrayList<>(attributes); // unfreeze it attributes.add(a); } @@ -340,32 +339,31 @@ class Attribute implements Comparable, Constants { if (attributes == null) return null; if (!attributes.contains(a)) return null; if (!(attributes instanceof ArrayList)) - attributes = new ArrayList(attributes); // unfreeze it + attributes = new ArrayList<>(attributes); // unfreeze it attributes.remove(a); return a; } public Attribute getAttribute(int n) { - return (Attribute) attributes.get(n); + return attributes.get(n); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { if (attributes == null) return; - for (Iterator i = attributes.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : attributes) { a.visitRefs(this, mode, refs); } } - static final List noAttributes = Arrays.asList(new Object[0]); + static final List noAttributes = Arrays.asList(new Attribute[0]); - public List getAttributes() { + public List getAttributes() { if (attributes == null) return noAttributes; return attributes; } - public void setAttributes(List attrList) { + public void setAttributes(List attrList) { if (attrList.isEmpty()) attributes = null; else @@ -374,8 +372,7 @@ class Attribute implements Comparable, Constants { public Attribute getAttribute(String attrName) { if (attributes == null) return null; - for (Iterator i = attributes.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : attributes) { if (a.name().equals(attrName)) return a; } @@ -384,8 +381,7 @@ class Attribute implements Comparable, Constants { public Attribute getAttribute(Layout attrDef) { if (attributes == null) return null; - for (Iterator i = attributes.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : attributes) { if (a.layout() == attrDef) return a; } @@ -457,14 +453,8 @@ class Attribute implements Comparable, Constants { public String layout() { return layout; } public Attribute canonicalInstance() { return canon; } - // Cache of name reference. - private Entry nameRef; // name, for use by visitRefs public Entry getNameRef() { - Entry nameRef = this.nameRef; - if (nameRef == null) { - this.nameRef = nameRef = ConstantPool.getUtf8Entry(name()); - } - return nameRef; + return ConstantPool.getUtf8Entry(name()); } public boolean isEmpty() { return layout == ""; } @@ -834,14 +824,14 @@ class Attribute implements Comparable, Constants { */ static //private Layout.Element[] tokenizeLayout(Layout self, int curCble, String layout) { - ArrayList col = new ArrayList(layout.length()); + ArrayList col = new ArrayList<>(layout.length()); tokenizeLayout(self, curCble, layout, col); Layout.Element[] res = new Layout.Element[col.size()]; col.toArray(res); return res; } static //private - void tokenizeLayout(Layout self, int curCble, String layout, ArrayList col) { + void tokenizeLayout(Layout self, int curCble, String layout, ArrayList col) { boolean prevBCI = false; for (int len = layout.length(), i = 0; i < len; ) { int start = i; @@ -899,7 +889,7 @@ class Attribute implements Comparable, Constants { case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']' kind = EK_UN; i = tokenizeSInt(e, layout, i); - ArrayList cases = new ArrayList(); + ArrayList cases = new ArrayList<>(); for (;;) { // Keep parsing cases until we hit the default case. if (layout.charAt(i++) != '(') @@ -1053,7 +1043,7 @@ class Attribute implements Comparable, Constants { } static //private String[] splitBodies(String layout) { - ArrayList bodies = new ArrayList(); + ArrayList bodies = new ArrayList<>(); // Parse several independent layout bodies: "[foo][bar]...[baz]" for (int i = 0; i < layout.length(); i++) { if (layout.charAt(i++) != '[') @@ -1132,7 +1122,9 @@ class Attribute implements Comparable, Constants { int parseIntBefore(String layout, int dash) { int end = dash; int beg = end; - while (beg > 0 && isDigit(layout.charAt(beg-1))) --beg; + while (beg > 0 && isDigit(layout.charAt(beg-1))) { + --beg; + } if (beg == end) return Integer.parseInt("empty"); // skip backward over a sign if (beg >= 1 && layout.charAt(beg-1) == '-') --beg; @@ -1145,7 +1137,9 @@ class Attribute implements Comparable, Constants { int end = beg; int limit = layout.length(); if (end < limit && layout.charAt(end) == '-') ++end; - while (end < limit && isDigit(layout.charAt(end))) ++end; + while (end < limit && isDigit(layout.charAt(end))) { + ++end; + } if (beg == end) return Integer.parseInt("empty"); return Integer.parseInt(layout.substring(beg, end)); } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java index ab138bc2d91..ac6199abe25 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package com.sun.java.util.jar.pack; -import java.io.*; import java.util.*; /** @@ -40,20 +39,13 @@ class ConstantPool implements Constants { return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE); } - // Uniquification tables for factory methods: - private static final HashMap utf8Entries = new HashMap(); - private static final HashMap classEntries = new HashMap(); - private static final HashMap literalEntries = new HashMap(); - private static final HashMap signatureEntries = new HashMap(); - private static final HashMap descriptorEntries = new HashMap(); - private static final HashMap memberEntries = new HashMap(); - /** Factory for Utf8 string constants. * Used for well-known strings like "SourceFile", "", etc. * Also used to back up more complex constant pool entries, like Class. */ public static synchronized Utf8Entry getUtf8Entry(String value) { - Utf8Entry e = (Utf8Entry) utf8Entries.get(value); + Map utf8Entries = Utils.getUtf8Entries(); + Utf8Entry e = utf8Entries.get(value); if (e == null) { e = new Utf8Entry(value); utf8Entries.put(e.stringValue(), e); @@ -62,9 +54,10 @@ class ConstantPool implements Constants { } /** Factory for Class constants. */ public static synchronized ClassEntry getClassEntry(String name) { - ClassEntry e = (ClassEntry) classEntries.get(name); + Map classEntries = Utils.getClassEntries(); + ClassEntry e = classEntries.get(name); if (e == null) { - e = (ClassEntry) new ClassEntry(getUtf8Entry(name)); + e = new ClassEntry(getUtf8Entry(name)); assert(name.equals(e.stringValue())); classEntries.put(e.stringValue(), e); } @@ -72,7 +65,8 @@ class ConstantPool implements Constants { } /** Factory for literal constants (String, Integer, etc.). */ public static synchronized LiteralEntry getLiteralEntry(Comparable value) { - LiteralEntry e = (LiteralEntry) literalEntries.get(value); + Map literalEntries = Utils.getLiteralEntries(); + LiteralEntry e = literalEntries.get(value); if (e == null) { if (value instanceof String) e = new StringEntry(getUtf8Entry((String)value)); @@ -89,7 +83,8 @@ class ConstantPool implements Constants { /** Factory for signature (type) constants. */ public static synchronized SignatureEntry getSignatureEntry(String type) { - SignatureEntry e = (SignatureEntry) signatureEntries.get(type); + Map signatureEntries = Utils.getSignatureEntries(); + SignatureEntry e = signatureEntries.get(type); if (e == null) { e = new SignatureEntry(type); assert(e.stringValue().equals(type)); @@ -104,8 +99,9 @@ class ConstantPool implements Constants { /** Factory for descriptor (name-and-type) constants. */ public static synchronized DescriptorEntry getDescriptorEntry(Utf8Entry nameRef, SignatureEntry typeRef) { + Map descriptorEntries = Utils.getDescriptorEntries(); String key = DescriptorEntry.stringValueOf(nameRef, typeRef); - DescriptorEntry e = (DescriptorEntry) descriptorEntries.get(key); + DescriptorEntry e = descriptorEntries.get(key); if (e == null) { e = new DescriptorEntry(nameRef, typeRef); assert(e.stringValue().equals(key)) @@ -121,8 +117,9 @@ class ConstantPool implements Constants { /** Factory for member reference constants. */ public static synchronized MemberEntry getMemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) { + Map memberEntries = Utils.getMemberEntries(); String key = MemberEntry.stringValueOf(tag, classRef, descRef); - MemberEntry e = (MemberEntry) memberEntries.get(key); + MemberEntry e = memberEntries.get(key); if (e == null) { e = new MemberEntry(tag, classRef, descRef); assert(e.stringValue().equals(key)) @@ -489,8 +486,9 @@ class ConstantPool implements Constants { String[] parts = structureSignature(value); formRef = getUtf8Entry(parts[0]); classRefs = new ClassEntry[parts.length-1]; - for (int i = 1; i < parts.length; i++) - classRefs[i-1] = getClassEntry(parts[i]); + for (int i = 1; i < parts.length; i++) { + classRefs[i - 1] = getClassEntry(parts[i]); + } hashCode(); // force computation of valueHash } protected int computeValueHash() { @@ -527,8 +525,9 @@ class ConstantPool implements Constants { String stringValueOf(Utf8Entry formRef, ClassEntry[] classRefs) { String[] parts = new String[1+classRefs.length]; parts[0] = formRef.stringValue(); - for (int i = 1; i < parts.length; i++) - parts[i] = classRefs[i-1].stringValue(); + for (int i = 1; i < parts.length; i++) { + parts[i] = classRefs[i - 1].stringValue(); + } return flattenSignature(parts).intern(); } @@ -543,19 +542,23 @@ class ConstantPool implements Constants { int size = 0; for (int i = min; i < max; i++) { switch (form.charAt(i)) { - case 'D': - case 'J': - if (countDoublesTwice) size++; - break; - case '[': - // Skip rest of array info. - while (form.charAt(i) == '[') ++i; - break; - case ';': - continue; - default: - assert(0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i))); - break; + case 'D': + case 'J': + if (countDoublesTwice) { + size++; + } + break; + case '[': + // Skip rest of array info. + while (form.charAt(i) == '[') { + ++i; + } + break; + case ';': + continue; + default: + assert (0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i))); + break; } size++; } @@ -586,8 +589,9 @@ class ConstantPool implements Constants { s = "/" + formRef.stringValue(); } int i; - while ((i = s.indexOf(';')) >= 0) - s = s.substring(0,i) + s.substring(i+1); + while ((i = s.indexOf(';')) >= 0) { + s = s.substring(0, i) + s.substring(i + 1); + } return s; } } @@ -732,11 +736,11 @@ class ConstantPool implements Constants { clearIndex(); this.cpMap = cpMap; } - protected Index(String debugName, Collection cpMapList) { + protected Index(String debugName, Collection cpMapList) { this(debugName); setMap(cpMapList); } - protected void setMap(Collection cpMapList) { + protected void setMap(Collection cpMapList) { cpMap = new Entry[cpMapList.size()]; cpMapList.toArray(cpMap); setMap(cpMap); @@ -756,11 +760,13 @@ class ConstantPool implements Constants { // // As a special hack, if flattenSigs, signatures are // treated as equivalent entries of cpMap. This is wrong - // fron a Collection point of view, because contains() + // from a Collection point of view, because contains() // reports true for signatures, but the iterator() // never produces them! private int findIndexOf(Entry e) { - if (indexKey == null) initializeIndex(); + if (indexKey == null) { + initializeIndex(); + } int probe = findIndexLocation(e); if (indexKey[probe] != e) { if (flattenSigs && e.tag == CONSTANT_Signature) { @@ -832,7 +838,9 @@ class ConstantPool implements Constants { System.out.println("initialize Index "+debugName+" ["+size()+"]"); int hsize0 = (int)((cpMap.length + 10) * 1.5); int hsize = 1; - while (hsize < hsize0) hsize <<= 1; + while (hsize < hsize0) { + hsize <<= 1; + } indexKey = new Entry[hsize]; indexValue = new int[hsize]; for (int i = 0; i < cpMap.length; i++) { @@ -855,7 +863,7 @@ class ConstantPool implements Constants { return toArray(new Entry[size()]); } public Object clone() { - return new Index(debugName, (Entry[]) cpMap.clone()); + return new Index(debugName, cpMap.clone()); } public String toString() { return "Index "+debugName+" ["+size()+"]"; @@ -901,22 +909,24 @@ class ConstantPool implements Constants { public static Index[] partition(Index ix, int[] keys) { // %%% Should move this into class Index. - ArrayList parts = new ArrayList(); + ArrayList> parts = new ArrayList<>(); Entry[] cpMap = ix.cpMap; assert(keys.length == cpMap.length); for (int i = 0; i < keys.length; i++) { int key = keys[i]; if (key < 0) continue; - while (key >= parts.size()) parts.add(null); - ArrayList part = (ArrayList) parts.get(key); + while (key >= parts.size()) { + parts.add(null); + } + List part = parts.get(key); if (part == null) { - parts.set(key, part = new ArrayList()); + parts.set(key, part = new ArrayList<>()); } part.add(cpMap[i]); } Index[] indexes = new Index[parts.size()]; for (int key = 0; key < indexes.length; key++) { - ArrayList part = (ArrayList) parts.get(key); + List part = parts.get(key); if (part == null) continue; indexes[key] = new Index(ix.debugName+"/part#"+key, part); assert(indexes[key].indexOf(part.get(0)) == 0); @@ -1048,9 +1058,10 @@ class ConstantPool implements Constants { whichClasses[i] = whichClass; } perClassIndexes = partition(allMembers, whichClasses); - for (int i = 0; i < perClassIndexes.length; i++) - assert(perClassIndexes[i]==null - || perClassIndexes[i].assertIsSorted()); + for (int i = 0; i < perClassIndexes.length; i++) { + assert (perClassIndexes[i] == null || + perClassIndexes[i].assertIsSorted()); + } indexByTagAndClass[tag] = perClassIndexes; } int whichClass = allClasses.indexOf(classRef); @@ -1113,7 +1124,7 @@ class ConstantPool implements Constants { * Also, discard null from cpRefs. */ public static - void completeReferencesIn(Set cpRefs, boolean flattenSigs) { + void completeReferencesIn(Set cpRefs, boolean flattenSigs) { cpRefs.remove(null); for (ListIterator work = new ArrayList(cpRefs).listIterator(cpRefs.size()); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java index 50d145db99f..2630febb7c3 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package com.sun.java.util.jar.pack; -import java.lang.Error; import java.io.*; import java.text.MessageFormat; import java.util.*; @@ -35,10 +34,11 @@ import java.util.zip.*; /** Command line interface for Pack200. */ class Driver { - private static final ResourceBundle RESOURCE= ResourceBundle.getBundle("com.sun.java.util.jar.pack.DriverResource"); + private static final ResourceBundle RESOURCE = + ResourceBundle.getBundle("com.sun.java.util.jar.pack.DriverResource"); public static void main(String[] ava) throws IOException { - ArrayList av = new ArrayList(Arrays.asList(ava)); + ArrayList av = new ArrayList<>(Arrays.asList(ava)); boolean doPack = true; boolean doUnpack = false; @@ -61,7 +61,7 @@ class Driver { } // Collect engine properties here: - HashMap engProps = new HashMap(); + HashMap engProps = new HashMap<>(); engProps.put(verboseProp, System.getProperty(verboseProp)); String optionMap; @@ -75,7 +75,7 @@ class Driver { } // Collect argument properties here: - HashMap avProps = new HashMap(); + HashMap avProps = new HashMap<>(); try { for (;;) { String state = parseCommandOptions(av, optionMap, avProps); @@ -133,8 +133,9 @@ class Driver { if (engProps.get(verboseProp) != null) fileProps.list(System.out); propIn.close(); - for (Map.Entry me : fileProps.entrySet()) - engProps.put((String)me.getKey(), (String)me.getValue()); + for (Map.Entry me : fileProps.entrySet()) { + engProps.put((String) me.getKey(), (String) me.getValue()); + } } else if (state == "--version") { System.out.println(MessageFormat.format(RESOURCE.getString(DriverResource.VERSION), Driver.class.getName(), "1.31, 07/05/05")); return; @@ -493,7 +494,7 @@ class Driver { String resultString = null; // Convert options string into optLines dictionary. - TreeMap optmap = new TreeMap(); + TreeMap optmap = new TreeMap<>(); loadOptmap: for (String optline : options.split("\n")) { String[] words = optline.split("\\p{Space}+"); @@ -687,7 +688,9 @@ class Driver { // Report number of arguments consumed. args.subList(0, argp.nextIndex()).clear(); // Report any unconsumed partial argument. - while (pbp.hasPrevious()) args.add(0, pbp.previous()); + while (pbp.hasPrevious()) { + args.add(0, pbp.previous()); + } //System.out.println(args+" // "+properties+" -> "+resultString); return resultString; } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java index f8c55dc6656..c6d96085180 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,13 +28,8 @@ package com.sun.java.util.jar.pack; import java.nio.*; import java.io.*; -import java.nio.channels.*; -import java.util.Date; import java.util.jar.*; import java.util.zip.*; -import java.util.*; -//import com.sun.java.util.jar.pack.Pack200; - class NativeUnpack { // Pointer to the native unpacker obj @@ -91,13 +86,13 @@ class NativeUnpack { NativeUnpack(UnpackerImpl p200) { super(); _p200 = p200; - _props = p200._props; + _props = p200.props; p200._nunp = this; } // for JNI callbacks static private Object currentInstance() { - UnpackerImpl p200 = (UnpackerImpl) Utils.currentInstance.get(); + UnpackerImpl p200 = (UnpackerImpl) Utils.getTLGlobals(); return (p200 == null)? null: p200._nunp; } @@ -216,10 +211,10 @@ class NativeUnpack { ++_fileCount; updateProgress(); } + presetInput = getUnusedInput(); long consumed = finish(); if (_verbose > 0) Utils.log.info("bytes consumed = "+consumed); - presetInput = getUnusedInput(); if (presetInput == null && !Utils.isPackMagic(Utils.readMagic(in))) { break; diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java index 1ea04690ed8..29d217687c4 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java @@ -25,9 +25,9 @@ package com.sun.java.util.jar.pack; +import com.sun.java.util.jar.pack.Attribute.Layout; import java.lang.reflect.Modifier; import java.util.*; -import java.util.zip.*; import java.util.jar.*; import java.io.*; import com.sun.java.util.jar.pack.ConstantPool.*; @@ -77,10 +77,11 @@ class Package implements Constants { cp = new ConstantPool.IndexGroup(); classes.clear(); files.clear(); + BandStructure.nextSeqForDebug = 0; } int getPackageVersion() { - return (package_majver << 16) + (int)package_minver; + return (package_majver << 16) + package_minver; } // Special empty versions of Code and InnerClasses, used for markers. @@ -89,7 +90,7 @@ class Package implements Constants { public static final Attribute.Layout attrSourceFileSpecial; public static final Map attrDefs; static { - HashMap ad = new HashMap(2); + HashMap ad = new HashMap<>(3); attrCodeEmpty = Attribute.define(ad, ATTR_CONTEXT_METHOD, "Code", "").layout(); attrInnerClassesEmpty = Attribute.define(ad, ATTR_CONTEXT_CLASS, @@ -159,9 +160,9 @@ class Package implements Constants { } } - ArrayList classes = new ArrayList(); + ArrayList classes = new ArrayList<>(); - public List getClasses() { + public List getClasses() { return classes; } @@ -186,11 +187,11 @@ class Package implements Constants { ClassEntry[] interfaces; // Class parts - ArrayList fields; - ArrayList methods; + ArrayList fields; + ArrayList methods; //ArrayList attributes; // in Attribute.Holder.this.attributes // Note that InnerClasses may be collected at the package level. - ArrayList innerClasses; + ArrayList innerClasses; Class(int flags, ClassEntry thisClass, ClassEntry superClass, ClassEntry[] interfaces) { this.magic = JAVA_MAGIC; @@ -270,7 +271,7 @@ class Package implements Constants { if (a != olda) { if (verbose > 2) Utils.log.fine("recoding obvious SourceFile="+obvious); - List newAttrs = new ArrayList(getAttributes()); + List newAttrs = new ArrayList<>(getAttributes()); int where = newAttrs.indexOf(olda); newAttrs.set(where, a); setAttributes(newAttrs); @@ -295,12 +296,12 @@ class Package implements Constants { boolean hasInnerClasses() { return innerClasses != null; } - List getInnerClasses() { + List getInnerClasses() { return innerClasses; } - public void setInnerClasses(Collection ics) { - innerClasses = (ics == null) ? null : new ArrayList(ics); + public void setInnerClasses(Collection ics) { + innerClasses = (ics == null) ? null : new ArrayList(ics); // Edit the attribute list, if necessary. Attribute a = getAttribute(attrInnerClassesEmpty); if (innerClasses != null && a == null) @@ -318,19 +319,18 @@ class Package implements Constants { * The order of the resulting list is consistent * with that of Package.this.allInnerClasses. */ - public List computeGloballyImpliedICs() { - HashSet cpRefs = new HashSet(); + public List computeGloballyImpliedICs() { + HashSet cpRefs = new HashSet<>(); { // This block temporarily displaces this.innerClasses. - ArrayList innerClassesSaved = innerClasses; + ArrayList innerClassesSaved = innerClasses; innerClasses = null; // ignore for the moment visitRefs(VRM_CLASSIC, cpRefs); innerClasses = innerClassesSaved; } ConstantPool.completeReferencesIn(cpRefs, true); - HashSet icRefs = new HashSet(); - for (Iterator i = cpRefs.iterator(); i.hasNext(); ) { - Entry e = (Entry) i.next(); + HashSet icRefs = new HashSet<>(); + for (Entry e : cpRefs) { // Restrict cpRefs to InnerClasses entries only. if (!(e instanceof ClassEntry)) continue; // For every IC reference, add its outers also. @@ -345,9 +345,8 @@ class Package implements Constants { // This loop is structured this way so as to accumulate // entries into impliedICs in an order which reflects // the order of allInnerClasses. - ArrayList impliedICs = new ArrayList(); - for (Iterator i = allInnerClasses.iterator(); i.hasNext(); ) { - InnerClass ic = (InnerClass) i.next(); + ArrayList impliedICs = new ArrayList<>(); + for (InnerClass ic : allInnerClasses) { // This one is locally relevant if it describes // a member of the current class, or if the current // class uses it somehow. In the particular case @@ -366,10 +365,11 @@ class Package implements Constants { // Helper for both minimizing and expanding. // Computes a symmetric difference. - private List computeICdiff() { - List impliedICs = computeGloballyImpliedICs(); - List actualICs = getInnerClasses(); - if (actualICs == null) actualICs = Collections.EMPTY_LIST; + private List computeICdiff() { + List impliedICs = computeGloballyImpliedICs(); + List actualICs = getInnerClasses(); + if (actualICs == null) + actualICs = Collections.EMPTY_LIST; // Symmetric difference is calculated from I, A like this: // diff = (I+A) - (I*A) @@ -388,8 +388,8 @@ class Package implements Constants { // Diff is A since I is empty. } // (I*A) is non-trivial - HashSet center = new HashSet(actualICs); - center.retainAll(new HashSet(impliedICs)); + HashSet center = new HashSet<>(actualICs); + center.retainAll(new HashSet<>(impliedICs)); impliedICs.addAll(actualICs); impliedICs.removeAll(center); // Diff is now I^A = (I+A)-(I*A). @@ -407,9 +407,9 @@ class Package implements Constants { * to use the globally implied ICs changed. */ void minimizeLocalICs() { - List diff = computeICdiff(); - List actualICs = innerClasses; - List localICs; // will be the diff, modulo edge cases + List diff = computeICdiff(); + List actualICs = innerClasses; + List localICs; // will be the diff, modulo edge cases if (diff.isEmpty()) { // No diff, so transmit no attribute. localICs = null; @@ -439,12 +439,12 @@ class Package implements Constants { * Otherwise, return positive if any IC tuples were added. */ int expandLocalICs() { - List localICs = innerClasses; - List actualICs; + List localICs = innerClasses; + List actualICs; int changed; if (localICs == null) { // Diff was empty. (Common case.) - List impliedICs = computeGloballyImpliedICs(); + List impliedICs = computeGloballyImpliedICs(); if (impliedICs.isEmpty()) { actualICs = null; changed = 0; @@ -490,7 +490,7 @@ class Package implements Constants { protected Entry[] getCPMap() { return cpMap; } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { if (verbose > 2) Utils.log.fine("visitRefs "+this); // Careful: The descriptor is used by the package, // but the classfile breaks it into component refs. @@ -518,7 +518,7 @@ class Package implements Constants { super(flags, descriptor); assert(!descriptor.isMethod()); if (fields == null) - fields = new ArrayList(); + fields = new ArrayList<>(); boolean added = fields.add(this); assert(added); order = fields.size(); @@ -543,7 +543,7 @@ class Package implements Constants { super(flags, descriptor); assert(descriptor.isMethod()); if (methods == null) - methods = new ArrayList(); + methods = new ArrayList<>(); boolean added = methods.add(this); assert(added); } @@ -573,7 +573,7 @@ class Package implements Constants { code.strip(attrName); super.strip(attrName); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { super.visitRefs(mode, refs); if (code != null) { if (mode == VRM_CLASSIC) { @@ -614,7 +614,7 @@ class Package implements Constants { super.strip(attrName); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { if (verbose > 2) Utils.log.fine("visitRefs "+this); refs.add(thisClass); refs.add(superClass); @@ -641,7 +641,7 @@ class Package implements Constants { super.visitRefs(mode, refs); } - protected void visitInnerClassRefs(int mode, Collection refs) { + protected void visitInnerClassRefs(int mode, Collection refs) { Package.visitInnerClassRefs(innerClasses, mode, refs); } @@ -713,16 +713,15 @@ class Package implements Constants { } // What non-class files are in this unit? - ArrayList files = new ArrayList(); + ArrayList files = new ArrayList<>(); - public List getFiles() { + public List getFiles() { return files; } - public List getClassStubs() { - ArrayList classStubs = new ArrayList(classes.size()); - for (Iterator i = classes.iterator(); i.hasNext(); ) { - Class cls = (Class) i.next(); + public List getClassStubs() { + ArrayList classStubs = new ArrayList<>(classes.size()); + for (Class cls : classes) { assert(cls.file.isClassStub()); classStubs.add(cls.file); } @@ -840,7 +839,7 @@ class Package implements Constants { public InputStream getInputStream() { InputStream in = new ByteArrayInputStream(append.toByteArray()); if (prepend.size() == 0) return in; - ArrayList isa = new ArrayList(prepend.size()+1); + ArrayList isa = new ArrayList<>(prepend.size()+1); for (Iterator i = prepend.iterator(); i.hasNext(); ) { byte[] bytes = (byte[]) i.next(); isa.add(new ByteArrayInputStream(bytes)); @@ -849,7 +848,7 @@ class Package implements Constants { return new SequenceInputStream(Collections.enumeration(isa)); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { assert(name != null); refs.add(name); } @@ -877,8 +876,8 @@ class Package implements Constants { } // Is there a globally declared table of inner classes? - ArrayList allInnerClasses = new ArrayList(); - HashMap allInnerClassesByThis; + ArrayList allInnerClasses = new ArrayList<>(); + HashMap allInnerClassesByThis; public List getAllInnerClasses() { @@ -886,15 +885,14 @@ class Package implements Constants { } public - void setAllInnerClasses(Collection ics) { + void setAllInnerClasses(Collection ics) { assert(ics != allInnerClasses); allInnerClasses.clear(); allInnerClasses.addAll(ics); // Make an index: - allInnerClassesByThis = new HashMap(allInnerClasses.size()); - for (Iterator i = allInnerClasses.iterator(); i.hasNext(); ) { - InnerClass ic = (InnerClass) i.next(); + allInnerClassesByThis = new HashMap<>(allInnerClasses.size()); + for (InnerClass ic : allInnerClasses) { Object pic = allInnerClassesByThis.put(ic.thisClass, ic); assert(pic == null); // caller must ensure key uniqueness! } @@ -904,7 +902,7 @@ class Package implements Constants { public InnerClass getGlobalInnerClass(Entry thisClass) { assert(thisClass instanceof ClassEntry); - return (InnerClass) allInnerClassesByThis.get(thisClass); + return allInnerClassesByThis.get(thisClass); } static @@ -963,7 +961,7 @@ class Package implements Constants { return this.thisClass.compareTo(that.thisClass); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { refs.add(thisClass); if (mode == VRM_CLASSIC || !predictable) { // If the name can be demangled, the package omits @@ -980,7 +978,7 @@ class Package implements Constants { // Helper for building InnerClasses attributes. static private - void visitInnerClassRefs(Collection innerClasses, int mode, Collection refs) { + void visitInnerClassRefs(Collection innerClasses, int mode, Collection refs) { if (innerClasses == null) { return; // no attribute; nothing to do } @@ -1165,9 +1163,8 @@ class Package implements Constants { } } - protected void visitRefs(int mode, Collection refs) { - for (Iterator i = classes.iterator(); i.hasNext(); ) { - Class c = (Class)i.next(); + protected void visitRefs(int mode, Collection refs) { + for ( Class c : classes) { c.visitRefs(mode, refs); } if (mode != VRM_CLASSIC) { @@ -1259,7 +1256,7 @@ class Package implements Constants { } // Use this before writing the package file. - void buildGlobalConstantPool(Set requiredEntries) { + void buildGlobalConstantPool(Set requiredEntries) { if (verbose > 1) Utils.log.fine("Checking for unused CP entries"); requiredEntries.add(getRefString("")); // uconditionally present @@ -1291,9 +1288,8 @@ class Package implements Constants { // Use this before writing the class files. void ensureAllClassFiles() { - HashSet fileSet = new HashSet(files); - for (Iterator i = classes.iterator(); i.hasNext(); ) { - Class cls = (Class) i.next(); + HashSet fileSet = new HashSet<>(files); + for (Class cls : classes) { // Add to the end of ths list: if (!fileSet.contains(cls.file)) files.add(cls.file); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java index 9c285794303..449bbbeb5b1 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,11 @@ package com.sun.java.util.jar.pack; +import com.sun.java.util.jar.pack.Attribute.Layout; import java.util.*; import java.util.jar.*; -import java.util.zip.*; import java.io.*; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeEvent; /* @@ -41,31 +40,22 @@ import java.beans.PropertyChangeEvent; */ -public class PackerImpl implements Pack200.Packer { +public class PackerImpl extends TLGlobals implements Pack200.Packer { /** * Constructs a Packer object and sets the initial state of * the packer engines. */ - public PackerImpl() { - _props = new PropMap(); - //_props.getProperty() consults defaultProps invisibly. - //_props.putAll(defaultProps); - } - - - // Private stuff. - final PropMap _props; + public PackerImpl() {} /** * Get the set of options for the pack and unpack engines. * @return A sorted association of option key strings to option values. */ - public SortedMap properties() { - return _props; + public SortedMap properties() { + return props; } - //Driver routines /** @@ -78,21 +68,22 @@ public class PackerImpl implements Pack200.Packer { */ public void pack(JarFile in, OutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : - TimeZone.getDefault(); + TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) + ? null + : TimeZone.getDefault(); try { Utils.currentInstance.set(this); if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) { + if ("0".equals(props.getProperty(Pack200.Packer.EFFORT))) { Utils.copyJarFile(in, out); } else { (new DoPack()).run(in, out); - in.close(); } } finally { Utils.currentInstance.set(null); if (tz != null) TimeZone.setDefault(tz); + in.close(); } } @@ -112,21 +103,20 @@ public class PackerImpl implements Pack200.Packer { */ public void pack(JarInputStream in, OutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : + TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : TimeZone.getDefault(); try { Utils.currentInstance.set(this); if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) { + if ("0".equals(props.getProperty(Pack200.Packer.EFFORT))) { Utils.copyJarFile(in, out); } else { (new DoPack()).run(in, out); - in.close(); } } finally { Utils.currentInstance.set(null); if (tz != null) TimeZone.setDefault(tz); - + in.close(); } } /** @@ -134,7 +124,7 @@ public class PackerImpl implements Pack200.Packer { * @param listener An object to be invoked when a property is changed. */ public void addPropertyChangeListener(PropertyChangeListener listener) { - _props.addListener(listener); + props.addListener(listener); } /** @@ -142,7 +132,7 @@ public class PackerImpl implements Pack200.Packer { * @param listener The PropertyChange listener to be removed. */ public void removePropertyChangeListener(PropertyChangeListener listener) { - _props.removeListener(listener); + props.removeListener(listener); } @@ -151,11 +141,11 @@ public class PackerImpl implements Pack200.Packer { // The packer worker. private class DoPack { - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); { - _props.setInteger(Pack200.Packer.PROGRESS, 0); - if (verbose > 0) Utils.log.info(_props.toString()); + props.setInteger(Pack200.Packer.PROGRESS, 0); + if (verbose > 0) Utils.log.info(props.toString()); } // Here's where the bits are collected before getting packed: @@ -163,7 +153,7 @@ public class PackerImpl implements Pack200.Packer { final String unknownAttrCommand; { - String uaMode = _props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); + String uaMode = props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); if (!(Pack200.Packer.STRIP.equals(uaMode) || Pack200.Packer.PASS.equals(uaMode) || Pack200.Packer.ERROR.equals(uaMode))) { @@ -191,13 +181,12 @@ public class PackerImpl implements Pack200.Packer { }; for (int i = 0; i < ctypes.length; i++) { String pfx = keys[i]; - Map map = _props.prefixMap(pfx); - for (Iterator j = map.keySet().iterator(); j.hasNext(); ) { - String key = (String) j.next(); + Map map = props.prefixMap(pfx); + for (String key : map.keySet()) { assert(key.startsWith(pfx)); String name = key.substring(pfx.length()); - String layout = _props.getProperty(key); - Object lkey = Attribute.keyForLookup(ctypes[i], name); + String layout = props.getProperty(key); + Layout lkey = Attribute.keyForLookup(ctypes[i], name); if (Pack200.Packer.STRIP.equals(layout) || Pack200.Packer.PASS.equals(layout) || Pack200.Packer.ERROR.equals(layout)) { @@ -222,25 +211,25 @@ public class PackerImpl implements Pack200.Packer { } final boolean keepFileOrder - = _props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER); + = props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER); final boolean keepClassOrder - = _props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER); + = props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER); final boolean keepModtime - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME)); + = Pack200.Packer.KEEP.equals(props.getProperty(Pack200.Packer.MODIFICATION_TIME)); final boolean latestModtime - = Pack200.Packer.LATEST.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME)); + = Pack200.Packer.LATEST.equals(props.getProperty(Pack200.Packer.MODIFICATION_TIME)); final boolean keepDeflateHint - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.DEFLATE_HINT)); + = Pack200.Packer.KEEP.equals(props.getProperty(Pack200.Packer.DEFLATE_HINT)); { if (!keepModtime && !latestModtime) { - int modtime = _props.getTime(Pack200.Packer.MODIFICATION_TIME); + int modtime = props.getTime(Pack200.Packer.MODIFICATION_TIME); if (modtime != Constants.NO_MODTIME) { pkg.default_modtime = modtime; } } if (!keepDeflateHint) { - boolean deflate_hint = _props.getBoolean(Pack200.Packer.DEFLATE_HINT); + boolean deflate_hint = props.getBoolean(Pack200.Packer.DEFLATE_HINT); if (deflate_hint) { pkg.default_options |= Constants.AO_DEFLATE_HINT; } @@ -254,10 +243,10 @@ public class PackerImpl implements Pack200.Packer { final long segmentLimit; { long limit; - if (_props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals("")) + if (props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals("")) limit = -1; else - limit = _props.getLong(Pack200.Packer.SEGMENT_LIMIT); + limit = props.getLong(Pack200.Packer.SEGMENT_LIMIT); limit = Math.min(Integer.MAX_VALUE, limit); limit = Math.max(-1, limit); if (limit == -1) @@ -265,10 +254,10 @@ public class PackerImpl implements Pack200.Packer { segmentLimit = limit; } - final List passFiles; // parsed pack.pass.file options + final List passFiles; // parsed pack.pass.file options { // Which class files will be passed through? - passFiles = _props.getProperties(Pack200.Packer.PASS_FILE_PFX); + passFiles = props.getProperties(Pack200.Packer.PASS_FILE_PFX); for (ListIterator i = passFiles.listIterator(); i.hasNext(); ) { String file = (String) i.next(); if (file == null) { i.remove(); continue; } @@ -283,28 +272,28 @@ public class PackerImpl implements Pack200.Packer { { // Fill in permitted range of major/minor version numbers. int ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"min.class.majver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"min.class.majver")) != 0) pkg.min_class_majver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"min.class.minver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"min.class.minver")) != 0) pkg.min_class_minver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"max.class.majver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"max.class.majver")) != 0) pkg.max_class_majver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"max.class.minver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"max.class.minver")) != 0) pkg.max_class_minver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"package.minver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"package.minver")) != 0) pkg.package_minver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"package.majver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"package.majver")) != 0) pkg.package_majver = (short) ver; } { // Hook for testing: Forces use of special archive modes. - int opt = _props.getInteger(Utils.COM_PREFIX+"archive.options"); + int opt = props.getInteger(Utils.COM_PREFIX+"archive.options"); if (opt != 0) pkg.default_options |= opt; } - // (Done collecting options from _props.) + // (Done collecting options from props.) boolean isClassFile(String name) { if (!name.endsWith(".class")) return false; @@ -423,16 +412,18 @@ public class PackerImpl implements Pack200.Packer { Package.File file = null; // (5078608) : discount the resource files in META-INF // from segment computation. - long inflen = (isMetaInfFile(name)) ? 0L : - inFile.getInputLength(); + long inflen = (isMetaInfFile(name)) + ? 0L + : inFile.getInputLength(); if ((segmentSize += inflen) > segmentLimit) { segmentSize -= inflen; int nextCount = -1; // don't know; it's a stream flushPartial(out, nextCount); } - if (verbose > 1) + if (verbose > 1) { Utils.log.fine("Reading " + name); + } assert(je.isDirectory() == name.endsWith("/")); @@ -450,18 +441,18 @@ public class PackerImpl implements Pack200.Packer { } void run(JarFile in, OutputStream out) throws IOException { - List inFiles = scanJar(in); + List inFiles = scanJar(in); if (verbose > 0) Utils.log.info("Reading " + inFiles.size() + " files..."); int numDone = 0; - for (Iterator i = inFiles.iterator(); i.hasNext(); ) { - InFile inFile = (InFile) i.next(); + for (InFile inFile : inFiles) { String name = inFile.name; // (5078608) : discount the resource files completely from segmenting - long inflen = (isMetaInfFile(name)) ? 0L : - inFile.getInputLength() ; + long inflen = (isMetaInfFile(name)) + ? 0L + : inFile.getInputLength() ; if ((segmentSize += inflen) > segmentLimit) { segmentSize -= inflen; // Estimate number of remaining segments: @@ -530,11 +521,11 @@ public class PackerImpl implements Pack200.Packer { } void flushPartial(OutputStream out, int nextCount) throws IOException { - if (pkg.files.size() == 0 && pkg.classes.size() == 0) { + if (pkg.files.isEmpty() && pkg.classes.isEmpty()) { return; // do not flush an empty segment } flushPackage(out, Math.max(1, nextCount)); - _props.setInteger(Pack200.Packer.PROGRESS, 25); + props.setInteger(Pack200.Packer.PROGRESS, 25); // In case there will be another segment: makeNextPackage(); segmentCount += 1; @@ -543,10 +534,10 @@ public class PackerImpl implements Pack200.Packer { } void flushAll(OutputStream out) throws IOException { - _props.setInteger(Pack200.Packer.PROGRESS, 50); + props.setInteger(Pack200.Packer.PROGRESS, 50); flushPackage(out, 0); out.flush(); - _props.setInteger(Pack200.Packer.PROGRESS, 100); + props.setInteger(Pack200.Packer.PROGRESS, 100); segmentCount += 1; segmentTotalSize += segmentSize; segmentSize = 0; @@ -582,11 +573,11 @@ public class PackerImpl implements Pack200.Packer { pkg.trimStubs(); // Do some stripping, maybe. - if (_props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses"); // Must choose an archive version; PackageWriter does not. if (pkg.package_majver <= 0) pkg.choosePackageVersion(); @@ -606,11 +597,10 @@ public class PackerImpl implements Pack200.Packer { } } - List scanJar(JarFile jf) throws IOException { + List scanJar(JarFile jf) throws IOException { // Collect jar entries, preserving order. - List inFiles = new ArrayList(); - for (Enumeration e = jf.entries(); e.hasMoreElements(); ) { - JarEntry je = (JarEntry) e.nextElement(); + List inFiles = new ArrayList<>(); + for (JarEntry je : Collections.list(jf.entries())) { InFile inFile = new InFile(jf, je); assert(je.isDirectory() == inFile.name.endsWith("/")); inFiles.add(inFile); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java index 6b92236f82e..78c709f343d 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java @@ -91,7 +91,7 @@ class PropMap extends TreeMap { String.valueOf(Boolean.getBoolean(Utils.PACK_DEFAULT_TIMEZONE))); // The segment size is unlimited - props.put(Pack200.Packer.SEGMENT_LIMIT, ""); + props.put(Pack200.Packer.SEGMENT_LIMIT, "-1"); // Preserve file ordering by default. props.put(Pack200.Packer.KEEP_FILE_ORDER, Pack200.Packer.TRUE); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java new file mode 100644 index 00000000000..0e40bde8b63 --- /dev/null +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.java.util.jar.pack; + +import com.sun.java.util.jar.pack.ConstantPool.ClassEntry; +import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry; +import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry; +import com.sun.java.util.jar.pack.ConstantPool.MemberEntry; +import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; +import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedMap; + +/* + * @author ksrini + */ + +/* + * This class provides a container to hold the global variables, for packer + * and unpacker instances. This is typically stashed away in a ThreadLocal, + * and the storage is destroyed upon completion. Therefore any local + * references to these members must be eliminated appropriately to prevent a + * memory leak. + */ +class TLGlobals { + // Global environment + final PropMap props; + + // Needed by ConstantPool.java + private final Map utf8Entries; + private final Map classEntries; + private final Map literalEntries; + private final Map signatureEntries; + private final Map descriptorEntries; + private final Map memberEntries; + + TLGlobals() { + utf8Entries = new HashMap<>(); + classEntries = new HashMap<>(); + literalEntries = new HashMap<>(); + signatureEntries = new HashMap<>(); + descriptorEntries = new HashMap<>(); + memberEntries = new HashMap<>(); + props = new PropMap(); + } + + SortedMap getPropMap() { + return props; + } + + Map getUtf8Entries() { + return utf8Entries; + } + + Map getClassEntries() { + return classEntries; + } + + Map getLiteralEntries() { + return literalEntries; + } + + Map getDescriptorEntries() { + return descriptorEntries; + } + + Map getSignatureEntries() { + return signatureEntries; + } + + Map getMemberEntries() { + return memberEntries; + } +} diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java index d131a1255f4..11c8abf07f1 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.util.jar.*; import java.util.zip.*; import java.io.*; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeEvent; /* * Implementation of the Pack provider. @@ -40,7 +39,7 @@ import java.beans.PropertyChangeEvent; */ -public class UnpackerImpl implements Pack200.Unpacker { +public class UnpackerImpl extends TLGlobals implements Pack200.Unpacker { /** @@ -48,7 +47,7 @@ public class UnpackerImpl implements Pack200.Unpacker { * @param listener An object to be invoked when a property is changed. */ public void addPropertyChangeListener(PropertyChangeListener listener) { - _props.addListener(listener); + props.addListener(listener); } @@ -57,25 +56,19 @@ public class UnpackerImpl implements Pack200.Unpacker { * @param listener The PropertyChange listener to be removed. */ public void removePropertyChangeListener(PropertyChangeListener listener) { - _props.removeListener(listener); + props.removeListener(listener); } - public UnpackerImpl() { - _props = new PropMap(); - //_props.getProperty() consults defaultProps invisibly. - //_props.putAll(defaultProps); - } + public UnpackerImpl() {} - // Private stuff. - final PropMap _props; /** * Get the set of options for the pack and unpack engines. * @return A sorted association of option key strings to option values. */ - public SortedMap properties() { - return _props; + public SortedMap properties() { + return props; } // Back-pointer to NativeUnpacker, when active. @@ -101,19 +94,20 @@ public class UnpackerImpl implements Pack200.Unpacker { */ public void unpack(InputStream in0, JarOutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : - TimeZone.getDefault(); + TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) + ? null + : TimeZone.getDefault(); try { Utils.currentInstance.set(this); if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); BufferedInputStream in = new BufferedInputStream(in0); if (Utils.isJarMagic(Utils.readMagic(in))) { if (verbose > 0) Utils.log.info("Copying unpacked JAR file..."); Utils.copyJarFile(new JarInputStream(in), out); - } else if (_props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) { + } else if (props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) { (new DoUnpack()).run(in, out); in.close(); Utils.markJarFile(out); @@ -142,36 +136,38 @@ public class UnpackerImpl implements Pack200.Unpacker { // %%% Reconsider if native unpacker learns to memory-map the file. FileInputStream instr = new FileInputStream(in); unpack(instr, out); - if (_props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) { + if (props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) { in.delete(); } } private class DoUnpack { - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); { - _props.setInteger(Pack200.Unpacker.PROGRESS, 0); + props.setInteger(Pack200.Unpacker.PROGRESS, 0); } // Here's where the bits are read from disk: final Package pkg = new Package(); final boolean keepModtime - = Pack200.Packer.KEEP.equals(_props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP)); + = Pack200.Packer.KEEP.equals( + props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP)); final boolean keepDeflateHint - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP)); + = Pack200.Packer.KEEP.equals( + props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP)); final int modtime; final boolean deflateHint; { if (!keepModtime) { - modtime = _props.getTime(Utils.UNPACK_MODIFICATION_TIME); + modtime = props.getTime(Utils.UNPACK_MODIFICATION_TIME); } else { modtime = pkg.default_modtime; } deflateHint = (keepDeflateHint) ? false : - _props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT); + props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT); } // Checksum apparatus. @@ -181,7 +177,7 @@ public class UnpackerImpl implements Pack200.Unpacker { public void run(BufferedInputStream in, JarOutputStream out) throws IOException { if (verbose > 0) { - _props.list(System.out); + props.list(System.out); } for (int seg = 1; ; seg++) { unpackSegment(in, out); @@ -194,25 +190,26 @@ public class UnpackerImpl implements Pack200.Unpacker { } private void unpackSegment(InputStream in, JarOutputStream out) throws IOException { - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0"); + props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0"); // Process the output directory or jar output. new PackageReader(pkg, in).read(); - if (_props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug"); - if (_props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile"); - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50"); + if (props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug"); + if (props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile"); + props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50"); pkg.ensureAllClassFiles(); // Now write out the files. - HashSet classesToWrite = new HashSet(pkg.getClasses()); + HashSet classesToWrite = new HashSet<>(pkg.getClasses()); for (Iterator i = pkg.getFiles().iterator(); i.hasNext(); ) { Package.File file = (Package.File) i.next(); String name = file.nameString; JarEntry je = new JarEntry(Utils.getJarEntryName(name)); boolean deflate; - deflate = (keepDeflateHint) ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) || - ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) : - deflateHint; + deflate = (keepDeflateHint) + ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) || + ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) + : deflateHint; boolean needCRC = !deflate; // STORE mode requires CRC @@ -250,7 +247,7 @@ public class UnpackerImpl implements Pack200.Unpacker { Utils.log.info("Writing "+Utils.zeString((ZipEntry)je)); } assert(classesToWrite.isEmpty()); - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100"); + props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100"); pkg.reset(); // reset for the next segment, if any } } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java index 8edbed10c46..2dc47c41464 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,13 @@ package com.sun.java.util.jar.pack; +import com.sun.java.util.jar.pack.Attribute.Layout; +import com.sun.java.util.jar.pack.ConstantPool.ClassEntry; +import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry; +import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry; +import com.sun.java.util.jar.pack.ConstantPool.MemberEntry; +import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; +import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; import java.util.*; import java.util.jar.*; import java.util.zip.*; @@ -113,17 +120,46 @@ class Utils { */ static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200"; - // Keep a TLS point to the current Packer or Unpacker. - // This makes it simpler to supply environmental options + // Keep a TLS point to the global data and environment. + // This makes it simpler to supply environmental options // to the engine code, especially the native code. - static final ThreadLocal currentInstance = new ThreadLocal(); + static final ThreadLocal currentInstance = new ThreadLocal<>(); + + // convenience methods to access the TL globals + static TLGlobals getTLGlobals() { + return currentInstance.get(); + } + + static Map getUtf8Entries() { + return getTLGlobals().getUtf8Entries(); + } + + static Map getClassEntries() { + return getTLGlobals().getClassEntries(); + } + + static Map getLiteralEntries() { + return getTLGlobals().getLiteralEntries(); + } + + static Map getDescriptorEntries() { + return getTLGlobals().getDescriptorEntries(); + } + + static Map getSignatureEntries() { + return getTLGlobals().getSignatureEntries(); + } + + static Map getMemberEntries() { + return getTLGlobals().getMemberEntries(); + } static PropMap currentPropMap() { Object obj = currentInstance.get(); if (obj instanceof PackerImpl) - return ((PackerImpl)obj)._props; + return ((PackerImpl)obj).props; if (obj instanceof UnpackerImpl) - return ((UnpackerImpl)obj)._props; + return ((UnpackerImpl)obj).props; return null; } diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java index 4503d261fff..dec38eb752d 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java @@ -813,7 +813,8 @@ public final class Connection implements Runnable { try { while (true) { try { - inbuf = new byte[10]; + // type and length (at most 128 octets for long form) + inbuf = new byte[129]; offset = 0; seqlen = 0; diff --git a/jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java b/jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java index 4a4734d241c..97bafe3f9a6 100644 --- a/jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java +++ b/jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java @@ -474,7 +474,7 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice This is necessary for Receivers retrieved via MidiSystem.getReceiver() (which opens the device implicitely). */ - protected abstract class AbstractReceiver implements Receiver { + protected abstract class AbstractReceiver implements MidiDeviceReceiver { private boolean open = true; @@ -508,6 +508,10 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice AbstractMidiDevice.this.closeInternal(this); } + public MidiDevice getMidiDevice() { + return AbstractMidiDevice.this; + } + protected boolean isOpen() { return open; } @@ -529,7 +533,7 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice * Also, it has some optimizations regarding sending to the Receivers, * for known Receivers, and managing itself in the TransmitterList. */ - protected class BasicTransmitter implements Transmitter { + protected class BasicTransmitter implements MidiDeviceTransmitter { private Receiver receiver = null; TransmitterList tlist = null; @@ -568,6 +572,9 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice } } + public MidiDevice getMidiDevice() { + return AbstractMidiDevice.this; + } } // class BasicTransmitter diff --git a/jdk/src/share/classes/com/sun/media/sound/AudioFloatConverter.java b/jdk/src/share/classes/com/sun/media/sound/AudioFloatConverter.java index 45bd2a52c97..95068ed6126 100644 --- a/jdk/src/share/classes/com/sun/media/sound/AudioFloatConverter.java +++ b/jdk/src/share/classes/com/sun/media/sound/AudioFloatConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,8 +40,6 @@ import javax.sound.sampled.AudioFormat.Encoding; */ public abstract class AudioFloatConverter { - public static final Encoding PCM_FLOAT = new Encoding("PCM_FLOAT"); - /*************************************************************************** * * LSB Filter, used filter least significant byte in samples arrays. @@ -982,7 +980,7 @@ public abstract class AudioFloatConverter { format.getSampleSizeInBits() + 7) / 8) - 4); } } - } else if (format.getEncoding().equals(PCM_FLOAT)) { + } else if (format.getEncoding().equals(Encoding.PCM_FLOAT)) { if (format.getSampleSizeInBits() == 32) { if (format.isBigEndian()) conv = new AudioFloatConversion32B(); diff --git a/jdk/src/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java b/jdk/src/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java index 506eab542ac..0b73dca0666 100644 --- a/jdk/src/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java +++ b/jdk/src/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -175,7 +175,6 @@ public class AudioFloatFormatConverter extends FormatConversionProvider { for (int c = 0; c < targetChannels; c++) { for (int i = 0, ix = off + c; i < len2; i++, ix += cs) { b[ix] = conversion_buffer[i]; - ; } } } else if (targetChannels == 1) { @@ -186,7 +185,6 @@ public class AudioFloatFormatConverter extends FormatConversionProvider { for (int c = 1; c < sourceChannels; c++) { for (int i = c, ix = off; i < len2; i += cs, ix++) { b[ix] += conversion_buffer[i]; - ; } } float vol = 1f / ((float) sourceChannels); @@ -390,6 +388,7 @@ public class AudioFloatFormatConverter extends FormatConversionProvider { return -1; if (len < 0) return 0; + int offlen = off + len; int remain = len / nrofchannels; int destPos = 0; int in_end = ibuffer_len; @@ -423,7 +422,7 @@ public class AudioFloatFormatConverter extends FormatConversionProvider { for (int c = 0; c < nrofchannels; c++) { int ix = 0; float[] buff = cbuffer[c]; - for (int i = c; i < b.length; i += nrofchannels) { + for (int i = c + off; i < offlen; i += nrofchannels) { b[i] = buff[ix++]; } } @@ -447,7 +446,7 @@ public class AudioFloatFormatConverter extends FormatConversionProvider { } public long skip(long len) throws IOException { - if (len > 0) + if (len < 0) return 0; if (skipbuffer == null) skipbuffer = new float[1024 * targetFormat.getFrameSize()]; @@ -470,7 +469,7 @@ public class AudioFloatFormatConverter extends FormatConversionProvider { } private Encoding[] formats = { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, - AudioFloatConverter.PCM_FLOAT }; + Encoding.PCM_FLOAT }; public AudioInputStream getAudioInputStream(Encoding targetEncoding, AudioInputStream sourceStream) { @@ -482,7 +481,7 @@ public class AudioFloatFormatConverter extends FormatConversionProvider { float samplerate = format.getSampleRate(); int bits = format.getSampleSizeInBits(); boolean bigendian = format.isBigEndian(); - if (targetEncoding.equals(AudioFloatConverter.PCM_FLOAT)) + if (targetEncoding.equals(Encoding.PCM_FLOAT)) bits = 32; AudioFormat targetFormat = new AudioFormat(encoding, samplerate, bits, channels, channels * bits / 8, samplerate, bigendian); @@ -521,19 +520,19 @@ public class AudioFloatFormatConverter extends FormatConversionProvider { public Encoding[] getSourceEncodings() { return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, - AudioFloatConverter.PCM_FLOAT }; + Encoding.PCM_FLOAT }; } public Encoding[] getTargetEncodings() { return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, - AudioFloatConverter.PCM_FLOAT }; + Encoding.PCM_FLOAT }; } public Encoding[] getTargetEncodings(AudioFormat sourceFormat) { if (AudioFloatConverter.getConverter(sourceFormat) == null) return new Encoding[0]; return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, - AudioFloatConverter.PCM_FLOAT }; + Encoding.PCM_FLOAT }; } public AudioFormat[] getTargetFormats(Encoding targetEncoding, @@ -572,17 +571,17 @@ public class AudioFloatFormatConverter extends FormatConversionProvider { } } - if (targetEncoding.equals(AudioFloatConverter.PCM_FLOAT)) { - formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT, + if (targetEncoding.equals(Encoding.PCM_FLOAT)) { + formats.add(new AudioFormat(Encoding.PCM_FLOAT, AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4, AudioSystem.NOT_SPECIFIED, false)); - formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT, + formats.add(new AudioFormat(Encoding.PCM_FLOAT, AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4, AudioSystem.NOT_SPECIFIED, true)); - formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT, + formats.add(new AudioFormat(Encoding.PCM_FLOAT, AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8, AudioSystem.NOT_SPECIFIED, false)); - formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT, + formats.add(new AudioFormat(Encoding.PCM_FLOAT, AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8, AudioSystem.NOT_SPECIFIED, true)); } diff --git a/jdk/src/share/classes/com/sun/media/sound/AudioSynthesizerPropertyInfo.java b/jdk/src/share/classes/com/sun/media/sound/AudioSynthesizerPropertyInfo.java index c37f48ac37c..2c5e160a4bb 100644 --- a/jdk/src/share/classes/com/sun/media/sound/AudioSynthesizerPropertyInfo.java +++ b/jdk/src/share/classes/com/sun/media/sound/AudioSynthesizerPropertyInfo.java @@ -42,11 +42,14 @@ public class AudioSynthesizerPropertyInfo { */ public AudioSynthesizerPropertyInfo(String name, Object value) { this.name = name; - this.value = value; if (value instanceof Class) valueClass = (Class)value; - else if (value != null) - valueClass = value.getClass(); + else + { + this.value = value; + if (value != null) + valueClass = value.getClass(); + } } /** * The name of the property. diff --git a/jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java b/jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java index 6fdae7c3988..2b490dd6061 100644 --- a/jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java +++ b/jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -781,7 +781,7 @@ public class DLSSoundbank implements Soundbank { } if (sampleformat == 3) { audioformat = new AudioFormat( - AudioFloatConverter.PCM_FLOAT, samplerate, bits, + Encoding.PCM_FLOAT, samplerate, bits, channels, framesize, samplerate, false); } @@ -965,7 +965,7 @@ public class DLSSoundbank implements Soundbank { sampleformat = 1; else if (audioformat.getEncoding().equals(Encoding.PCM_SIGNED)) sampleformat = 1; - else if (audioformat.getEncoding().equals(AudioFloatConverter.PCM_FLOAT)) + else if (audioformat.getEncoding().equals(Encoding.PCM_FLOAT)) sampleformat = 3; fmt_chunk.writeUnsignedShort(sampleformat); diff --git a/jdk/src/share/classes/com/sun/media/sound/MidiDeviceReceiverEnvelope.java b/jdk/src/share/classes/com/sun/media/sound/MidiDeviceReceiverEnvelope.java new file mode 100644 index 00000000000..9a962bbd412 --- /dev/null +++ b/jdk/src/share/classes/com/sun/media/sound/MidiDeviceReceiverEnvelope.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.media.sound; + +import javax.sound.midi.*; + + +/** + * Helper class which allows to convert {@code Receiver} + * to {@code MidiDeviceReceiver}. + * + * @author Alex Menkov + */ +public class MidiDeviceReceiverEnvelope implements MidiDeviceReceiver { + + private final MidiDevice device; + private final Receiver receiver; + + /** + * Creates a new {@code MidiDeviceReceiverEnvelope} object which + * envelops the specified {@code Receiver} + * and is owned by the specified {@code MidiDevice}. + * + * @param device the owner {@code MidiDevice} + * @param receiver the {@code Receiver} to be enveloped + */ + public MidiDeviceReceiverEnvelope(MidiDevice device, Receiver receiver) { + if (device == null || receiver == null) { + throw new NullPointerException(); + } + this.device = device; + this.receiver = receiver; + } + + // Receiver implementation + public void close() { + receiver.close(); + } + + public void send(MidiMessage message, long timeStamp) { + receiver.send(message, timeStamp); + } + + // MidiDeviceReceiver implementation + public MidiDevice getMidiDevice() { + return device; + } + + /** + * Obtains the receiver enveloped + * by this {@code MidiDeviceReceiverEnvelope} object. + * + * @return the enveloped receiver + */ + public Receiver getReceiver() { + return receiver; + } +} diff --git a/jdk/src/share/classes/com/sun/media/sound/MidiDeviceTransmitterEnvelope.java b/jdk/src/share/classes/com/sun/media/sound/MidiDeviceTransmitterEnvelope.java new file mode 100644 index 00000000000..e20d430a042 --- /dev/null +++ b/jdk/src/share/classes/com/sun/media/sound/MidiDeviceTransmitterEnvelope.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.media.sound; + +import javax.sound.midi.*; + + +/** + * Helper class which allows to convert {@code Transmitter} + * to {@code MidiDeviceTransmitter}. + * + * @author Alex Menkov + */ +public class MidiDeviceTransmitterEnvelope implements MidiDeviceTransmitter { + + private final MidiDevice device; + private final Transmitter transmitter; + + /** + * Creates a new {@code MidiDeviceTransmitterEnvelope} object which + * envelops the specified {@code Transmitter} + * and is owned by the specified {@code MidiDevice}. + * + * @param device the owner {@code MidiDevice} + * @param transmitter the {@code Transmitter} to be enveloped + */ + public MidiDeviceTransmitterEnvelope(MidiDevice device, Transmitter transmitter) { + if (device == null || transmitter == null) { + throw new NullPointerException(); + } + this.device = device; + this.transmitter = transmitter; + } + + // Transmitter implementation + public void setReceiver(Receiver receiver) { + transmitter.setReceiver(receiver); + } + + public Receiver getReceiver() { + return transmitter.getReceiver(); + } + + public void close() { + transmitter.close(); + } + + + // MidiDeviceReceiver implementation + public MidiDevice getMidiDevice() { + return device; + } + + /** + * Obtains the transmitter enveloped + * by this {@code MidiDeviceTransmitterEnvelope} object. + * + * @return the enveloped transmitter + */ + public Transmitter getTransmitter() { + return transmitter; + } +} diff --git a/jdk/src/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java b/jdk/src/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java index 9ad439a6f69..bc3f63ac1a1 100644 --- a/jdk/src/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java +++ b/jdk/src/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java @@ -205,7 +205,8 @@ public class ModelByteBufferWavetable implements ModelWavetable { } if (buffer.array() == null) { return AudioFloatInputStream.getInputStream(new AudioInputStream( - buffer.getInputStream(), format, buffer.capacity())); + buffer.getInputStream(), format, + buffer.capacity() / format.getFrameSize())); } if (buffer8 != null) { if (format.getEncoding().equals(Encoding.PCM_SIGNED) diff --git a/jdk/src/share/classes/com/sun/media/sound/ModelInstrument.java b/jdk/src/share/classes/com/sun/media/sound/ModelInstrument.java index 5ecb84c0d17..89969209f71 100644 --- a/jdk/src/share/classes/com/sun/media/sound/ModelInstrument.java +++ b/jdk/src/share/classes/com/sun/media/sound/ModelInstrument.java @@ -56,7 +56,7 @@ public abstract class ModelInstrument extends Instrument { public ModelDirector getDirector(ModelPerformer[] performers, MidiChannel channel, ModelDirectedPlayer player) { - return new ModelStandardDirector(performers, player); + return new ModelStandardIndexedDirector(performers, player); } public ModelPerformer[] getPerformers() { diff --git a/jdk/src/share/classes/com/sun/media/sound/ModelStandardIndexedDirector.java b/jdk/src/share/classes/com/sun/media/sound/ModelStandardIndexedDirector.java new file mode 100644 index 00000000000..d5181e39cee --- /dev/null +++ b/jdk/src/share/classes/com/sun/media/sound/ModelStandardIndexedDirector.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.media.sound; + +/** + * A standard indexed director who chooses performers + * by there keyfrom,keyto,velfrom,velto properties. + * + * @author Karl Helgason + */ +public class ModelStandardIndexedDirector implements ModelDirector { + + ModelPerformer[] performers; + ModelDirectedPlayer player; + boolean noteOnUsed = false; + boolean noteOffUsed = false; + + // Variables needed for index + byte[][] trantables; + int[] counters; + int[][] mat; + + public ModelStandardIndexedDirector(ModelPerformer[] performers, + ModelDirectedPlayer player) { + this.performers = performers; + this.player = player; + for (int i = 0; i < performers.length; i++) { + ModelPerformer p = performers[i]; + if (p.isReleaseTriggered()) { + noteOffUsed = true; + } else { + noteOnUsed = true; + } + } + buildindex(); + } + + private int[] lookupIndex(int x, int y) { + if ((x >= 0) && (x < 128) && (y >= 0) && (y < 128)) { + int xt = trantables[0][x]; + int yt = trantables[1][y]; + if (xt != -1 && yt != -1) { + return mat[xt + yt * counters[0]]; + } + } + return null; + } + + private int restrict(int value) { + if(value < 0) return 0; + if(value > 127) return 127; + return value; + } + + private void buildindex() { + trantables = new byte[2][129]; + counters = new int[trantables.length]; + for (ModelPerformer performer : performers) { + int keyFrom = performer.getKeyFrom(); + int keyTo = performer.getKeyTo(); + int velFrom = performer.getVelFrom(); + int velTo = performer.getVelTo(); + if (keyFrom > keyTo) continue; + if (velFrom > velTo) continue; + keyFrom = restrict(keyFrom); + keyTo = restrict(keyTo); + velFrom = restrict(velFrom); + velTo = restrict(velTo); + trantables[0][keyFrom] = 1; + trantables[0][keyTo + 1] = 1; + trantables[1][velFrom] = 1; + trantables[1][velTo + 1] = 1; + } + for (int d = 0; d < trantables.length; d++) { + byte[] trantable = trantables[d]; + int transize = trantable.length; + for (int i = transize - 1; i >= 0; i--) { + if (trantable[i] == 1) { + trantable[i] = -1; + break; + } + trantable[i] = -1; + } + int counter = -1; + for (int i = 0; i < transize; i++) { + if (trantable[i] != 0) { + counter++; + if (trantable[i] == -1) + break; + } + trantable[i] = (byte) counter; + } + counters[d] = counter; + } + mat = new int[counters[0] * counters[1]][]; + int ix = 0; + for (ModelPerformer performer : performers) { + int keyFrom = performer.getKeyFrom(); + int keyTo = performer.getKeyTo(); + int velFrom = performer.getVelFrom(); + int velTo = performer.getVelTo(); + if (keyFrom > keyTo) continue; + if (velFrom > velTo) continue; + keyFrom = restrict(keyFrom); + keyTo = restrict(keyTo); + velFrom = restrict(velFrom); + velTo = restrict(velTo); + int x_from = trantables[0][keyFrom]; + int x_to = trantables[0][keyTo + 1]; + int y_from = trantables[1][velFrom]; + int y_to = trantables[1][velTo + 1]; + if (x_to == -1) + x_to = counters[0]; + if (y_to == -1) + y_to = counters[1]; + for (int y = y_from; y < y_to; y++) { + int i = x_from + y * counters[0]; + for (int x = x_from; x < x_to; x++) { + int[] mprev = mat[i]; + if (mprev == null) { + mat[i] = new int[] { ix }; + } else { + int[] mnew = new int[mprev.length + 1]; + mnew[mnew.length - 1] = ix; + for (int k = 0; k < mprev.length; k++) + mnew[k] = mprev[k]; + mat[i] = mnew; + } + i++; + } + } + ix++; + } + } + + public void close() { + } + + public void noteOff(int noteNumber, int velocity) { + if (!noteOffUsed) + return; + int[] plist = lookupIndex(noteNumber, velocity); + if(plist == null) return; + for (int i : plist) { + ModelPerformer p = performers[i]; + if (p.isReleaseTriggered()) { + player.play(i, null); + } + } + } + + public void noteOn(int noteNumber, int velocity) { + if (!noteOnUsed) + return; + int[] plist = lookupIndex(noteNumber, velocity); + if(plist == null) return; + for (int i : plist) { + ModelPerformer p = performers[i]; + if (!p.isReleaseTriggered()) { + player.play(i, null); + } + } + } +} diff --git a/jdk/src/share/classes/com/sun/media/sound/SoftChannel.java b/jdk/src/share/classes/com/sun/media/sound/SoftChannel.java index 1526cef99c1..1fc20b75b83 100644 --- a/jdk/src/share/classes/com/sun/media/sound/SoftChannel.java +++ b/jdk/src/share/classes/com/sun/media/sound/SoftChannel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,7 +116,7 @@ public class SoftChannel implements MidiChannel, ModelDirectedPlayer { protected int tuning_program = 0; protected SoftInstrument current_instrument = null; protected ModelChannelMixer current_mixer = null; - private ModelDirector current_director = null; + protected ModelDirector current_director = null; // Controller Destination Settings protected int cds_control_number = -1; @@ -1264,13 +1264,16 @@ public class SoftChannel implements MidiChannel, ModelDirectedPlayer { } public void programChange(int bank, int program) { - bank = restrict7Bit(bank); + bank = restrict14Bit(bank); program = restrict7Bit(program); synchronized (control_mutex) { mainmixer.activity(); - this.bank = bank; - this.program = program; - current_instrument = null; + if(this.bank != bank || this.program != program) + { + this.bank = bank; + this.program = program; + current_instrument = null; + } } } diff --git a/jdk/src/share/classes/com/sun/media/sound/SoftMixingMixer.java b/jdk/src/share/classes/com/sun/media/sound/SoftMixingMixer.java index e6b9ee4ec7a..abc31cb8fa1 100644 --- a/jdk/src/share/classes/com/sun/media/sound/SoftMixingMixer.java +++ b/jdk/src/share/classes/com/sun/media/sound/SoftMixingMixer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,16 +118,16 @@ public class SoftMixingMixer implements Mixer { AudioSystem.NOT_SPECIFIED, bits, channels, channels * bits / 8, AudioSystem.NOT_SPECIFIED, true)); } - formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT, + formats.add(new AudioFormat(Encoding.PCM_FLOAT, AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4, AudioSystem.NOT_SPECIFIED, false)); - formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT, + formats.add(new AudioFormat(Encoding.PCM_FLOAT, AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4, AudioSystem.NOT_SPECIFIED, true)); - formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT, + formats.add(new AudioFormat(Encoding.PCM_FLOAT, AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8, AudioSystem.NOT_SPECIFIED, false)); - formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT, + formats.add(new AudioFormat(Encoding.PCM_FLOAT, AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8, AudioSystem.NOT_SPECIFIED, true)); } diff --git a/jdk/src/share/classes/com/sun/media/sound/SoftReceiver.java b/jdk/src/share/classes/com/sun/media/sound/SoftReceiver.java index e7c230e5122..03a0067f4ad 100644 --- a/jdk/src/share/classes/com/sun/media/sound/SoftReceiver.java +++ b/jdk/src/share/classes/com/sun/media/sound/SoftReceiver.java @@ -27,6 +27,7 @@ package com.sun.media.sound; import java.util.TreeMap; import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiDeviceReceiver; import javax.sound.midi.MidiMessage; import javax.sound.midi.ShortMessage; diff --git a/jdk/src/share/classes/com/sun/media/sound/SoftSynthesizer.java b/jdk/src/share/classes/com/sun/media/sound/SoftSynthesizer.java index 1c33dfc48a3..a868bd441a2 100644 --- a/jdk/src/share/classes/com/sun/media/sound/SoftSynthesizer.java +++ b/jdk/src/share/classes/com/sun/media/sound/SoftSynthesizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,16 +25,25 @@ package com.sun.media.sound; +import java.io.BufferedInputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.lang.ref.WeakReference; -import java.security.AccessControlException; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; import javax.sound.midi.Instrument; import javax.sound.midi.MidiChannel; @@ -182,6 +191,7 @@ public class SoftSynthesizer implements AudioSynthesizer, // 1: DLS Voice Allocation protected int voice_allocation_mode = 0; + protected boolean load_default_soundbank = false; protected boolean reverb_light = true; protected boolean reverb_on = true; protected boolean chorus_on = true; @@ -226,8 +236,6 @@ public class SoftSynthesizer implements AudioSynthesizer, = new HashMap(); private Map inslist = new HashMap(); - private Map availlist - = new HashMap(); private Map loadedlist = new HashMap(); @@ -275,10 +283,12 @@ public class SoftSynthesizer implements AudioSynthesizer, synchronized (control_mutex) { if (channels != null) for (SoftChannel c : channels) + { c.current_instrument = null; + c.current_director = null; + } for (Instrument instrument : instruments) { String pat = patchToString(instrument.getPatch()); - availlist.remove(pat); SoftInstrument softins = new SoftInstrument((ModelInstrument) instrument); inslist.put(pat, softins); @@ -341,6 +351,7 @@ public class SoftSynthesizer implements AudioSynthesizer, number_of_midi_channels = (Integer)items[10].value; jitter_correction = (Boolean)items[11].value; reverb_light = (Boolean)items[12].value; + load_default_soundbank = (Boolean)items[13].value; } private String patchToString(Patch patch) { @@ -578,7 +589,9 @@ public class SoftSynthesizer implements AudioSynthesizer, c.current_instrument = null; inslist.remove(pat); loadedlist.remove(pat); - availlist.remove(pat); + for (int i = 0; i < channels.length; i++) { + channels[i].allSoundOff(); + } } } @@ -600,7 +613,7 @@ public class SoftSynthesizer implements AudioSynthesizer, return false; synchronized (control_mutex) { - if (!loadedlist.containsValue(to) && !availlist.containsValue(to)) + if (!loadedlist.containsValue(to)) throw new IllegalArgumentException("Instrument to is not loaded."); unloadInstrument(from); ModelMappedInstrument mfrom = new ModelMappedInstrument( @@ -609,118 +622,155 @@ public class SoftSynthesizer implements AudioSynthesizer, } } - public synchronized Soundbank getDefaultSoundbank() { - if (defaultSoundBank == null) { - try { - File javahome = new File(System.getProperties().getProperty( - "java.home")); - File libaudio = new File(new File(javahome, "lib"), "audio"); + public Soundbank getDefaultSoundbank() { + synchronized (SoftSynthesizer.class) { + if (defaultSoundBank != null) + return defaultSoundBank; - if (libaudio.exists()) { - File foundfile = null; - File[] files = libaudio.listFiles(); - if (files != null) { - for (int i = 0; i < files.length; i++) { - File file = files[i]; - if (file.isFile()) { - String lname = file.getName().toLowerCase(); - if (lname.endsWith(".sf2") || - lname.endsWith(".dls")) { - if (foundfile == null || (file.length() > - foundfile.length())) { - foundfile = file; + List> actions = + new ArrayList>(); + + actions.add(new PrivilegedAction() { + public InputStream run() { + File javahome = new File(System.getProperties() + .getProperty("java.home")); + File libaudio = new File(new File(javahome, "lib"), "audio"); + if (libaudio.exists()) { + File foundfile = null; + File[] files = libaudio.listFiles(); + if (files != null) { + for (int i = 0; i < files.length; i++) { + File file = files[i]; + if (file.isFile()) { + String lname = file.getName().toLowerCase(); + if (lname.endsWith(".sf2") + || lname.endsWith(".dls")) { + if (foundfile == null + || (file.length() > foundfile + .length())) { + foundfile = file; + } } } } } - } - if (foundfile != null) { - try { - Soundbank sbk = MidiSystem.getSoundbank(foundfile); - defaultSoundBank = sbk; - return defaultSoundBank; - } catch (Exception e) { - //e.printStackTrace(); + if (foundfile != null) { + try { + return new FileInputStream(foundfile); + } catch (IOException e) { + } } } + return null; } + }); - if (System.getProperties().getProperty("os.name") - .startsWith("Windows")) { - File gm_dls = new File(System.getenv("SystemRoot") - + "\\system32\\drivers\\gm.dls"); - if (gm_dls.exists()) { - try { - Soundbank sbk = MidiSystem.getSoundbank(gm_dls); - defaultSoundBank = sbk; - return defaultSoundBank; - } catch (Exception e) { - //e.printStackTrace(); + actions.add(new PrivilegedAction() { + public InputStream run() { + if (System.getProperties().getProperty("os.name") + .startsWith("Windows")) { + File gm_dls = new File(System.getenv("SystemRoot") + + "\\system32\\drivers\\gm.dls"); + if (gm_dls.exists()) { + try { + return new FileInputStream(gm_dls); + } catch (IOException e) { + } } } + return null; } - } catch (AccessControlException e) { - } catch (Exception e) { - //e.printStackTrace(); - } + }); - File userhome = null; - File emg_soundbank_file = null; + actions.add(new PrivilegedAction() { + public InputStream run() { + /* + * Try to load saved generated soundbank + */ + File userhome = new File(System.getProperty("user.home"), + ".gervill"); + File emg_soundbank_file = new File(userhome, + "soundbank-emg.sf2"); + if (emg_soundbank_file.exists()) { + try { + return new FileInputStream(emg_soundbank_file); + } catch (IOException e) { + } + } + return null; + } + }); - /* - * Try to load saved generated soundbank - */ - try { - userhome = new File(System.getProperty("user.home"), - ".gervill"); - emg_soundbank_file = new File(userhome, "soundbank-emg.sf2"); - Soundbank sbk = MidiSystem.getSoundbank(emg_soundbank_file); - defaultSoundBank = sbk; - return defaultSoundBank; - } catch (AccessControlException e) { - } catch (Exception e) { - //e.printStackTrace(); + for (PrivilegedAction action : actions) { + try { + InputStream is = AccessController.doPrivileged(action); + if(is == null) continue; + Soundbank sbk; + try { + sbk = MidiSystem.getSoundbank(new BufferedInputStream(is)); + } finally { + is.close(); + } + if (sbk != null) { + defaultSoundBank = sbk; + return defaultSoundBank; + } + } catch (Exception e) { + } } try { - /* - * Generate emergency soundbank + * Generate emergency soundbank */ defaultSoundBank = EmergencySoundbank.createSoundbank(); - - /* - * Save generated soundbank to disk for faster future use. - */ - if(defaultSoundBank != null) - { - if(!userhome.exists()) userhome.mkdirs(); - if(!emg_soundbank_file.exists()) - ((SF2Soundbank)defaultSoundBank).save(emg_soundbank_file); - } } catch (Exception e) { - //e.printStackTrace(); } + if (defaultSoundBank != null) { + /* + * Save generated soundbank to disk for faster future use. + */ + OutputStream out = AccessController + .doPrivileged(new PrivilegedAction() { + public OutputStream run() { + try { + File userhome = new File(System + .getProperty("user.home"), + ".gervill"); + if (!userhome.exists()) + userhome.mkdirs(); + File emg_soundbank_file = new File( + userhome, "soundbank-emg.sf2"); + if (emg_soundbank_file.exists()) + return null; + return new FileOutputStream( + emg_soundbank_file); + } catch (IOException e) { + } catch (SecurityException e) { + } + return null; + } + }); + if (out != null) { + try { + ((SF2Soundbank) defaultSoundBank).save(out); + out.close(); + } catch (IOException e) { + } + } + } } return defaultSoundBank; } public Instrument[] getAvailableInstruments() { - if (!isOpen()) { - Soundbank defsbk = getDefaultSoundbank(); - if (defsbk == null) - return new Instrument[0]; - return defsbk.getInstruments(); - } - - synchronized (control_mutex) { - ModelInstrument[] inslist_array = - new ModelInstrument[availlist.values().size()]; - availlist.values().toArray(inslist_array); - Arrays.sort(inslist_array, new ModelInstrumentComparator()); - return inslist_array; - } + Soundbank defsbk = getDefaultSoundbank(); + if (defsbk == null) + return new Instrument[0]; + Instrument[] inslist_array = defsbk.getInstruments(); + Arrays.sort(inslist_array, new ModelInstrumentComparator()); + return inslist_array; } public Instrument[] getLoadedInstruments() { @@ -794,6 +844,31 @@ public class SoftSynthesizer implements AudioSynthesizer, return info; } + private Properties getStoredProperties() { + return AccessController + .doPrivileged(new PrivilegedAction() { + public Properties run() { + Properties p = new Properties(); + String notePath = "/com/sun/media/sound/softsynthesizer"; + try { + Preferences prefroot = Preferences.userRoot(); + if (prefroot.nodeExists(notePath)) { + Preferences prefs = prefroot.node(notePath); + String[] prefs_keys = prefs.keys(); + for (String prefs_key : prefs_keys) { + String val = prefs.get(prefs_key, null); + if (val != null) + p.setProperty(prefs_key, val); + } + } + } catch (BackingStoreException e) { + } catch (SecurityException e) { + } + return p; + } + }); + } + public AudioSynthesizerPropertyInfo[] getPropertyInfo(Map info) { List list = new ArrayList(); @@ -861,17 +936,92 @@ public class SoftSynthesizer implements AudioSynthesizer, item.description = "Turn light reverb mode on or off"; list.add(item); + item = new AudioSynthesizerPropertyInfo("load default soundbank", o?load_default_soundbank:true); + item.description = "Enabled/disable loading default soundbank"; + list.add(item); + AudioSynthesizerPropertyInfo[] items; items = list.toArray(new AudioSynthesizerPropertyInfo[list.size()]); - if (info != null) - for (AudioSynthesizerPropertyInfo item2: items) { - Object v = info.get(item2.name); + Properties storedProperties = getStoredProperties(); + + for (AudioSynthesizerPropertyInfo item2 : items) { + Object v = (info == null) ? null : info.get(item2.name); + v = (v != null) ? v : storedProperties.getProperty(item2.name); + if (v != null) { Class c = (item2.valueClass); - if (v != null) - if (c.isInstance(v)) - item2.value = v; + if (c.isInstance(v)) + item2.value = v; + else if (v instanceof String) { + String s = (String) v; + if (c == Boolean.class) { + if (s.equalsIgnoreCase("true")) + item2.value = Boolean.TRUE; + if (s.equalsIgnoreCase("false")) + item2.value = Boolean.FALSE; + } else if (c == AudioFormat.class) { + int channels = 2; + boolean signed = true; + boolean bigendian = false; + int bits = 16; + float sampleRate = 44100f; + try { + StringTokenizer st = new StringTokenizer(s, ", "); + String prevToken = ""; + while (st.hasMoreTokens()) { + String token = st.nextToken().toLowerCase(); + if (token.equals("mono")) + channels = 1; + if (token.startsWith("channel")) + channels = Integer.parseInt(prevToken); + if (token.contains("unsigned")) + signed = false; + if (token.equals("big-endian")) + bigendian = true; + if (token.equals("bit")) + bits = Integer.parseInt(prevToken); + if (token.equals("hz")) + sampleRate = Float.parseFloat(prevToken); + prevToken = token; + } + item2.value = new AudioFormat(sampleRate, bits, + channels, signed, bigendian); + } catch (NumberFormatException e) { + } + + } else + try { + if (c == Byte.class) + item2.value = Byte.valueOf(s); + else if (c == Short.class) + item2.value = Short.valueOf(s); + else if (c == Integer.class) + item2.value = Integer.valueOf(s); + else if (c == Long.class) + item2.value = Long.valueOf(s); + else if (c == Float.class) + item2.value = Float.valueOf(s); + else if (c == Double.class) + item2.value = Double.valueOf(s); + } catch (NumberFormatException e) { + } + } else if (v instanceof Number) { + Number n = (Number) v; + if (c == Byte.class) + item2.value = Byte.valueOf(n.byteValue()); + if (c == Short.class) + item2.value = Short.valueOf(n.shortValue()); + if (c == Integer.class) + item2.value = Integer.valueOf(n.intValue()); + if (c == Long.class) + item2.value = Long.valueOf(n.longValue()); + if (c == Float.class) + item2.value = Float.valueOf(n.floatValue()); + if (c == Double.class) + item2.value = Double.valueOf(n.doubleValue()); + } } + } return items; } @@ -1007,11 +1157,12 @@ public class SoftSynthesizer implements AudioSynthesizer, if (targetFormat != null) setFormat(targetFormat); - Soundbank defbank = getDefaultSoundbank(); - if (defbank != null) { - loadAllInstruments(defbank); - availlist.putAll(loadedlist); - loadedlist.clear(); + if (load_default_soundbank) + { + Soundbank defbank = getDefaultSoundbank(); + if (defbank != null) { + loadAllInstruments(defbank); + } } voices = new SoftVoice[maxpoly]; @@ -1117,7 +1268,6 @@ public class SoftSynthesizer implements AudioSynthesizer, } inslist.clear(); - availlist.clear(); loadedlist.clear(); tunings.clear(); diff --git a/jdk/src/share/classes/com/sun/media/sound/SoftVoice.java b/jdk/src/share/classes/com/sun/media/sound/SoftVoice.java index 6f891959dca..8e8fd5ecee0 100644 --- a/jdk/src/share/classes/com/sun/media/sound/SoftVoice.java +++ b/jdk/src/share/classes/com/sun/media/sound/SoftVoice.java @@ -279,9 +279,12 @@ public class SoftVoice extends VoiceStatus { } protected void updateTuning(SoftTuning newtuning) { + tuning = newtuning; tunedKey = tuning.getTuning(note) / 100.0; if (!portamento) { co_noteon_keynumber[0] = tunedKey * (1.0 / 128.0); + if(performer == null) + return; int[] c = performer.midi_connections[4]; if (c == null) return; @@ -433,6 +436,8 @@ public class SoftVoice extends VoiceStatus { } protected void setPolyPressure(int pressure) { + if(performer == null) + return; int[] c = performer.midi_connections[2]; if (c == null) return; @@ -441,6 +446,8 @@ public class SoftVoice extends VoiceStatus { } protected void setChannelPressure(int pressure) { + if(performer == null) + return; int[] c = performer.midi_connections[1]; if (c == null) return; @@ -449,6 +456,8 @@ public class SoftVoice extends VoiceStatus { } protected void controlChange(int controller, int value) { + if(performer == null) + return; int[] c = performer.midi_ctrl_connections[controller]; if (c == null) return; @@ -457,6 +466,8 @@ public class SoftVoice extends VoiceStatus { } protected void nrpnChange(int controller, int value) { + if(performer == null) + return; int[] c = performer.midi_nrpn_connections.get(controller); if (c == null) return; @@ -465,6 +476,8 @@ public class SoftVoice extends VoiceStatus { } protected void rpnChange(int controller, int value) { + if(performer == null) + return; int[] c = performer.midi_rpn_connections.get(controller); if (c == null) return; @@ -473,6 +486,8 @@ public class SoftVoice extends VoiceStatus { } protected void setPitchBend(int bend) { + if(performer == null) + return; int[] c = performer.midi_connections[0]; if (c == null) return; @@ -499,6 +514,8 @@ public class SoftVoice extends VoiceStatus { co_noteon_on[0] = -1; + if(performer == null) + return; int[] c = performer.midi_connections[3]; if (c == null) return; @@ -527,6 +544,8 @@ public class SoftVoice extends VoiceStatus { co_noteon_on[0] = 0; + if(performer == null) + return; int[] c = performer.midi_connections[3]; if (c == null) return; @@ -543,6 +562,8 @@ public class SoftVoice extends VoiceStatus { sustain = true; co_noteon_on[0] = 1; + if(performer == null) + return; int[] c = performer.midi_connections[3]; if (c == null) return; @@ -555,6 +576,11 @@ public class SoftVoice extends VoiceStatus { active = false; stopping = false; audiostarted = false; + instrument = null; + performer = null; + connections = null; + extendedConnectionBlocks = null; + channelmixer = null; if (osc_stream != null) try { osc_stream.close(); diff --git a/jdk/src/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java b/jdk/src/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java index 69304dc2a64..14a1848baaf 100644 --- a/jdk/src/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java +++ b/jdk/src/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -271,7 +271,7 @@ public class WaveExtensibleFileReader extends AudioFileReader { bits, channels, framesize, samplerate, false, p); } } else if (subFormat.equals(SUBTYPE_IEEE_FLOAT)) { - audioformat = new AudioFormat(AudioFloatConverter.PCM_FLOAT, + audioformat = new AudioFormat(Encoding.PCM_FLOAT, samplerate, bits, channels, framesize, samplerate, false, p); } else throw new UnsupportedAudioFileException(); diff --git a/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileReader.java b/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileReader.java index bbb8095c959..8db4113b702 100644 --- a/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileReader.java +++ b/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import java.net.URL; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; @@ -102,7 +103,7 @@ public class WaveFloatFileReader extends AudioFileReader { throw new UnsupportedAudioFileException(); AudioFormat audioformat = new AudioFormat( - AudioFloatConverter.PCM_FLOAT, samplerate, bits, channels, + Encoding.PCM_FLOAT, samplerate, bits, channels, framesize, samplerate, false); AudioFileFormat fileformat = new AudioFileFormat( AudioFileFormat.Type.WAVE, audioformat, diff --git a/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileWriter.java b/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileWriter.java index 324e868211c..a61792bacc4 100644 --- a/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileWriter.java +++ b/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.io.OutputStream; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.AudioFileFormat.Type; @@ -48,8 +49,7 @@ public class WaveFloatFileWriter extends AudioFileWriter { public Type[] getAudioFileTypes(AudioInputStream stream) { - if (!stream.getFormat().getEncoding().equals( - AudioFloatConverter.PCM_FLOAT)) + if (!stream.getFormat().getEncoding().equals(Encoding.PCM_FLOAT)) return new Type[0]; return new Type[] { Type.WAVE }; } @@ -58,8 +58,7 @@ public class WaveFloatFileWriter extends AudioFileWriter { if (!Type.WAVE.equals(type)) throw new IllegalArgumentException("File type " + type + " not supported."); - if (!stream.getFormat().getEncoding().equals( - AudioFloatConverter.PCM_FLOAT)) + if (!stream.getFormat().getEncoding().equals(Encoding.PCM_FLOAT)) throw new IllegalArgumentException("File format " + stream.getFormat() + " not supported."); } diff --git a/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java b/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java index 2f7478b4e26..cc3ebbfc21b 100644 --- a/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -518,7 +518,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern setReadOnly(true); setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); setEscapeProcessing(true); - setTypeMap(null); + //setTypeMap(null); checkTransactionalWriter(); //Instantiating the vector for MatchColumns @@ -679,7 +679,10 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern } else if (obj instanceof Clob) { obj = new SerialClob((Clob)obj); } else if (obj instanceof java.sql.Array) { - obj = new SerialArray((java.sql.Array)obj, map); + if(map != null) + obj = new SerialArray((java.sql.Array)obj, map); + else + obj = new SerialArray((java.sql.Array)obj); } ((Row)currentRow).initColumnObject(i, obj); @@ -762,7 +765,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern if( conn != null){ // JDBC 4.0 mandates as does the Java EE spec that all DataBaseMetaData methods // must be implemented, therefore, the previous fix for 5055528 is being backed out - dbmslocatorsUpdateCopy = conn.getMetaData().locatorsUpdateCopy(); + dbmslocatorsUpdateCopy = conn.getMetaData().locatorsUpdateCopy(); } } @@ -6322,6 +6325,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern crs.RowSetMD = RowSetMD; crs.numRows = 1; crs.cursorPos = 0; + crs.setTypeMap(this.getTypeMap()); // make sure we don't get someone playing with these // %%% is this now necessary ??? @@ -10114,7 +10118,7 @@ a * during the deserialization process * */ - protected void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { // Default state initialization happens here ois.defaultReadObject(); // Initialization of transient Res Bundle happens here . @@ -10125,5 +10129,15 @@ a } } - static final long serialVersionUID =1884577171200622428L; + + //------------------------- JDBC 4.1 ----------------------------------- + public T getObject(int columnIndex, Class type) throws SQLException { + throw new SQLFeatureNotSupportedException("Not supported yet."); + } + + public T getObject(String columnLabel, Class type) throws SQLException { + throw new SQLFeatureNotSupportedException("Not supported yet."); + } + + static final long serialVersionUID =1884577171200622428L; } diff --git a/jdk/src/share/classes/com/sun/rowset/FilteredRowSetImpl.java b/jdk/src/share/classes/com/sun/rowset/FilteredRowSetImpl.java index dd765d84c93..a9becf17d37 100644 --- a/jdk/src/share/classes/com/sun/rowset/FilteredRowSetImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/FilteredRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1746,5 +1746,23 @@ public class FilteredRowSetImpl extends WebRowSetImpl implements Serializable, C onInsertRow = false; super.insertRow(); } - static final long serialVersionUID = 6178454588413509360L; + + /** + * This method re populates the resBundle + * during the deserialization process + * + */ + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Default state initialization happens here + ois.defaultReadObject(); + // Initialization of transient Res Bundle happens here . + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + + } + + static final long serialVersionUID = 6178454588413509360L; } // end FilteredRowSetImpl class diff --git a/jdk/src/share/classes/com/sun/rowset/JdbcRowSetImpl.java b/jdk/src/share/classes/com/sun/rowset/JdbcRowSetImpl.java index 3c34ccf61e9..34178d4984d 100644 --- a/jdk/src/share/classes/com/sun/rowset/JdbcRowSetImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/JdbcRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { private Vector strMatchColumns; - protected transient JdbcRowSetResourceBundle jdbcResBundle; + protected transient JdbcRowSetResourceBundle resBundle; /** * Constructs a default JdbcRowSet object. @@ -140,7 +140,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { rs = null; try { - jdbcResBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); } catch(IOException ioe) { throw new RuntimeException(ioe); } @@ -154,42 +154,42 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { try { setShowDeleted(false); } catch(SQLException sqle) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setshowdeleted").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setshowdeleted").toString() + sqle.getLocalizedMessage()); } try { setQueryTimeout(0); } catch(SQLException sqle) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setquerytimeout").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setquerytimeout").toString() + sqle.getLocalizedMessage()); } try { setMaxRows(0); } catch(SQLException sqle) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmaxrows").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setmaxrows").toString() + sqle.getLocalizedMessage()); } try { setMaxFieldSize(0); } catch(SQLException sqle) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmaxfieldsize").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setmaxfieldsize").toString() + sqle.getLocalizedMessage()); } try { setEscapeProcessing(true); } catch(SQLException sqle) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setescapeprocessing").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setescapeprocessing").toString() + sqle.getLocalizedMessage()); } try { setConcurrency(ResultSet.CONCUR_UPDATABLE); } catch (SQLException sqle) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setconcurrency").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setconcurrency").toString() + sqle.getLocalizedMessage()); } @@ -198,7 +198,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { try { setType(ResultSet.TYPE_SCROLL_INSENSITIVE); } catch(SQLException sqle){ - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.settype").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.settype").toString() + sqle.getLocalizedMessage()); } @@ -207,7 +207,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { try { setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); } catch(SQLException sqle){ - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.settransactionisolation").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.settransactionisolation").toString() + sqle.getLocalizedMessage()); } @@ -263,7 +263,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { rs = null; try { - jdbcResBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); } catch(IOException ioe) { throw new RuntimeException(ioe); } @@ -338,7 +338,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { rs = null; try { - jdbcResBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); } catch(IOException ioe) { throw new RuntimeException(ioe); } @@ -430,7 +430,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { rs = res; try { - jdbcResBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); } catch(IOException ioe) { throw new RuntimeException(ioe); } @@ -517,7 +517,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { // to the db, implies undesirable state so throw exception if (conn == null && ps == null && rs == null ) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.invalstate").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.invalstate").toString()); } } @@ -593,28 +593,28 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { try { ps.setEscapeProcessing(getEscapeProcessing()); } catch (SQLException ex) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setescapeprocessing").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setescapeprocessing").toString() + ex.getLocalizedMessage()); } try { ps.setMaxFieldSize(getMaxFieldSize()); } catch (SQLException ex) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmaxfieldsize").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setmaxfieldsize").toString() + ex.getLocalizedMessage()); } try { ps.setMaxRows(getMaxRows()); } catch (SQLException ex) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmaxrows").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setmaxrows").toString() + ex.getLocalizedMessage()); } try { ps.setQueryTimeout(getQueryTimeout()); } catch (SQLException ex) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setquerytimeout").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setquerytimeout").toString() + ex.getLocalizedMessage()); } @@ -651,7 +651,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { } } catch (javax.naming.NamingException ex) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.connect").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.connect").toString()); } } else if (getUrl() != null) { @@ -681,7 +681,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { } ps = conn.prepareStatement(getCommand(),ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE); } catch (SQLException ex) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.prepare").toString() + + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.prepare").toString() + ex.getLocalizedMessage()); if (ps != null) @@ -721,15 +721,15 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { if (param[0] instanceof java.sql.Date || param[0] instanceof java.sql.Time || param[0] instanceof java.sql.Timestamp) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.detecteddate")); + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.detecteddate")); if (param[1] instanceof java.util.Calendar) { - System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.detectedcalendar")); + System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.detectedcalendar")); ps.setDate(i + 1, (java.sql.Date)param[0], (java.util.Calendar)param[1]); continue; } else { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString()); } } @@ -770,7 +770,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { (java.io.InputStream)param[0], ((Integer)param[1]).intValue()); default: - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString()); } } @@ -784,7 +784,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { continue; } - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString()); } else { // common case - this catches all SQL92 types @@ -3749,7 +3749,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { for( int j= 0 ;j < columnIdxes.length; j++) { i_val = (Integer.parseInt(iMatchColumns.get(j).toString())); if(columnIdxes[j] != i_val) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols").toString()); } } @@ -3776,7 +3776,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { for(int j = 0 ;j < columnIdxes.length; j++) { if( !columnIdxes[j].equals(strMatchColumns.get(j)) ){ - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols").toString()); } } @@ -3800,7 +3800,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { String []str_temp = new String[strMatchColumns.size()]; if( strMatchColumns.get(0) == null) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmatchcols").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.setmatchcols").toString()); } strMatchColumns.copyInto(str_temp); @@ -3825,7 +3825,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { i_val = ((Integer)iMatchColumns.get(0)).intValue(); if( i_val == -1 ) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmatchcols").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.setmatchcols").toString()); } @@ -3859,7 +3859,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { for(int j = 0 ; j < columnIdxes.length; j++) { if( columnIdxes[j] < 0 ) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols1").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols1").toString()); } } for(int i = 0 ;i < columnIdxes.length; i++) { @@ -3886,7 +3886,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { for(int j = 0; j < columnNames.length; j++) { if( columnNames[j] == null || columnNames[j].equals("")) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols2").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols2").toString()); } } for( int i = 0; i < columnNames.length; i++) { @@ -3915,7 +3915,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { public void setMatchColumn(int columnIdx) throws SQLException { // validate, if col is ok to be set if(columnIdx < 0) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols1").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols1").toString()); } else { // set iMatchColumn iMatchColumns.set(0, new Integer(columnIdx)); @@ -3941,7 +3941,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { public void setMatchColumn(String columnName) throws SQLException { // validate, if col is ok to be set if(columnName.equals(null) || ((columnName = columnName.trim()) == "" )) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols2").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols2").toString()); } else { // set strMatchColumn strMatchColumns.set(0, columnName); @@ -3966,9 +3966,9 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { public void unsetMatchColumn(int columnIdx) throws SQLException { // check if we are unsetting the SAME column if(! iMatchColumns.get(0).equals(new Integer(columnIdx) ) ) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.unsetmatch").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.unsetmatch").toString()); } else if(strMatchColumns.get(0) != null) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.usecolname").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.usecolname").toString()); } else { // that is, we are unsetting it. iMatchColumns.set(0, new Integer(-1)); @@ -3995,9 +3995,9 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { columnName = columnName.trim(); if(!((strMatchColumns.get(0)).equals(columnName))) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.unsetmatch").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.unsetmatch").toString()); } else if( ((Integer)(iMatchColumns.get(0))).intValue() > 0) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.usecolid").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.usecolid").toString()); } else { strMatchColumns.set(0, null); // that is, we are unsetting it. } @@ -4152,7 +4152,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { private void checkTypeConcurrency() throws SQLException { if(rs.getType() == TYPE_FORWARD_ONLY || rs.getConcurrency() == CONCUR_READ_ONLY) { - throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.resnotupd").toString()); + throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.resnotupd").toString()); } } @@ -4642,7 +4642,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public SQLXML getSQLXML(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4653,7 +4653,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @throws SQLException if a database access error occurs */ public SQLXML getSQLXML(String colName) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4668,7 +4668,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public RowId getRowId(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4683,7 +4683,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public RowId getRowId(String columnName) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4699,7 +4699,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public void updateRowId(int columnIndex, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4715,7 +4715,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public void updateRowId(String columnName, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4725,7 +4725,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public int getHoldability() throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4736,7 +4736,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public boolean isClosed() throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4748,7 +4748,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public void updateNString(int columnIndex, String nString) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4760,7 +4760,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public void updateNString(String columnName, String nString) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -4773,7 +4773,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public void updateNClob(int columnIndex, NClob nClob) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4785,7 +4785,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public void updateNClob(String columnName, NClob nClob) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4800,7 +4800,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public NClob getNClob(int i) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -4816,7 +4816,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 6.0 */ public NClob getNClob(String colName) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } public T unwrap(java.lang.Class iface) throws java.sql.SQLException{ @@ -4836,7 +4836,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4848,7 +4848,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4863,7 +4863,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public void setRowId(int parameterIndex, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4877,7 +4877,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public void setRowId(String parameterName, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -4897,7 +4897,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public void setNString(int parameterIndex, String value) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -4925,7 +4925,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4940,7 +4940,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public void setNClob(String parameterName, NClob value) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -4960,7 +4960,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public java.io.Reader getNCharacterStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -4980,7 +4980,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public java.io.Reader getNCharacterStream(String columnName) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -4996,7 +4996,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5013,7 +5013,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public void updateSQLXML(String columnName, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5031,7 +5031,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public String getNString(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5049,7 +5049,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @since 1.6 */ public String getNString(String columnName) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5071,7 +5071,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { java.io.Reader x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5093,7 +5093,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { java.io.Reader x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5123,7 +5123,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { */ public void updateNCharacterStream(int columnIndex, java.io.Reader x) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5155,7 +5155,7 @@ bel is the name of the column */ public void updateNCharacterStream(String columnLabel, java.io.Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5188,7 +5188,7 @@ bel is the name of the column * @since 1.6 */ public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5221,7 +5221,7 @@ bel is the name of the column * @since 1.6 */ public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5256,7 +5256,7 @@ bel is the name of the column * @since 1.6 */ public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5291,7 +5291,7 @@ bel is the name of the column * @since 1.6 */ public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5323,7 +5323,7 @@ bel is the name of the column * @since 1.6 */ public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5355,7 +5355,7 @@ bel is the name of the column * @since 1.6 */ public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5389,7 +5389,7 @@ bel is the name of the column * @since 1.6 */ public void updateClob(int columnIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5424,7 +5424,7 @@ bel is the name of the column * @since 1.6 */ public void updateClob(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5458,7 +5458,7 @@ bel is the name of the column * @since 1.6 */ public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5492,7 +5492,7 @@ bel is the name of the column * @since 1.6 */ public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5528,7 +5528,7 @@ bel is the name of the column * @since 1.6 */ public void updateNClob(int columnIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5565,7 +5565,7 @@ bel is the name of the column * @since 1.6 */ public void updateNClob(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -5590,7 +5590,7 @@ bel is the name of the column public void updateAsciiStream(int columnIndex, java.io.InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5614,7 +5614,7 @@ bel is the name of the column public void updateBinaryStream(int columnIndex, java.io.InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5638,7 +5638,7 @@ bel is the name of the column public void updateCharacterStream(int columnIndex, java.io.Reader x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5662,7 +5662,7 @@ bel is the name of the column public void updateAsciiStream(String columnLabel, java.io.InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5687,7 +5687,7 @@ bel is the name of the column */ public void updateAsciiStream(int columnIndex, java.io.InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5713,7 +5713,7 @@ bel is the name of the column */ public void updateAsciiStream(String columnLabel, java.io.InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -5738,7 +5738,7 @@ bel is the name of the column public void updateBinaryStream(String columnLabel, java.io.InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5763,7 +5763,7 @@ bel is the name of the column */ public void updateBinaryStream(int columnIndex, java.io.InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -5790,7 +5790,7 @@ bel is the name of the column */ public void updateBinaryStream(String columnLabel, java.io.InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -5816,7 +5816,7 @@ bel is the name of the column public void updateCharacterStream(String columnLabel, java.io.Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5841,7 +5841,7 @@ bel is the name of the column */ public void updateCharacterStream(int columnIndex, java.io.Reader x) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5868,7 +5868,7 @@ bel is the name of the column */ public void updateCharacterStream(String columnLabel, java.io.Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -5885,7 +5885,7 @@ bel is the name of the column * @since 1.4 */ public void setURL(int parameterIndex, java.net.URL x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -5914,7 +5914,7 @@ bel is the name of the column */ public void setNClob(int parameterIndex, Reader reader) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -5942,7 +5942,7 @@ bel is the name of the column */ public void setNClob(String parameterName, Reader reader, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -5969,7 +5969,7 @@ bel is the name of the column */ public void setNClob(String parameterName, Reader reader) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -5996,7 +5996,7 @@ bel is the name of the column */ public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6012,7 +6012,7 @@ a * @since 1.6 */ public void setNClob(int parameterIndex, NClob value) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6029,7 +6029,7 @@ a */ public void setNString(String parameterName, String value) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6046,7 +6046,7 @@ a * @since 1.6 */ public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6066,7 +6066,7 @@ a */ public void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6092,7 +6092,7 @@ a * @since 1.6 */ public void setNCharacterStream(String parameterName, Reader value) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6118,7 +6118,7 @@ a */ public void setTimestamp(String parameterName, java.sql.Timestamp x, Calendar cal) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6144,7 +6144,7 @@ a */ public void setClob(String parameterName, Reader reader, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6163,7 +6163,7 @@ a * @since 1.6 */ public void setClob (String parameterName, Clob x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6188,7 +6188,7 @@ a */ public void setClob(String parameterName, Reader reader) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6210,7 +6210,7 @@ a */ public void setDate(String parameterName, java.sql.Date x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6236,7 +6236,7 @@ a */ public void setDate(String parameterName, java.sql.Date x, Calendar cal) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6256,7 +6256,7 @@ a */ public void setTime(String parameterName, java.sql.Time x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6282,7 +6282,7 @@ a */ public void setTime(String parameterName, java.sql.Time x, Calendar cal) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6308,7 +6308,7 @@ a */ public void setClob(int parameterIndex, Reader reader) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6333,7 +6333,7 @@ a */ public void setClob(int parameterIndex, Reader reader, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6363,7 +6363,7 @@ a */ public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6395,7 +6395,7 @@ a */ public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6426,7 +6426,7 @@ a */ public void setBlob(String parameterName, InputStream inputStream, long length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6444,7 +6444,7 @@ a * @since 1.6 */ public void setBlob (String parameterName, Blob x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6470,7 +6470,7 @@ a */ public void setBlob(String parameterName, InputStream inputStream) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6516,7 +6516,7 @@ a */ public void setObject(String parameterName, Object x, int targetSqlType, int scale) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6542,7 +6542,7 @@ a */ public void setObject(String parameterName, Object x, int targetSqlType) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6582,7 +6582,7 @@ a * @since 1.4 */ public void setObject(String parameterName, Object x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6609,7 +6609,7 @@ a */ public void setAsciiStream(String parameterName, java.io.InputStream x, int length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6636,7 +6636,7 @@ a */ public void setBinaryStream(String parameterName, java.io.InputStream x, int length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6665,7 +6665,7 @@ a public void setCharacterStream(String parameterName, java.io.Reader reader, int length) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6692,7 +6692,7 @@ a */ public void setAsciiStream(String parameterName, java.io.InputStream x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6719,7 +6719,7 @@ a */ public void setBinaryStream(String parameterName, java.io.InputStream x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6748,7 +6748,7 @@ a */ public void setCharacterStream(String parameterName, java.io.Reader reader) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6767,7 +6767,7 @@ a * @since 1.4 */ public void setBigDecimal(String parameterName, BigDecimal x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6788,7 +6788,7 @@ a * @since 1.4 */ public void setString(String parameterName, String x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6810,7 +6810,7 @@ a * @since 1.4 */ public void setBytes(String parameterName, byte x[]) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6830,7 +6830,7 @@ a */ public void setTimestamp(String parameterName, java.sql.Timestamp x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6847,7 +6847,7 @@ a * @since 1.4 */ public void setNull(String parameterName, int sqlType) throws SQLException { - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6884,7 +6884,7 @@ a */ public void setNull (String parameterName, int sqlType, String typeName) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6902,7 +6902,7 @@ a * @since 1.4 */ public void setBoolean(String parameterName, boolean x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6922,7 +6922,7 @@ a * @since 1.4 */ public void setByte(String parameterName, byte x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6941,7 +6941,7 @@ a * @since 1.4 */ public void setShort(String parameterName, short x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6960,7 +6960,7 @@ a * @since 1.4 */ public void setInt(String parameterName, int x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -6978,7 +6978,7 @@ a * @since 1.4 */ public void setLong(String parameterName, long x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } @@ -6997,7 +6997,7 @@ a * @since 1.4 */ public void setFloat(String parameterName, float x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -7015,7 +7015,7 @@ a * @since 1.4 */ public void setDouble(String parameterName, double x) throws SQLException{ - throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); + throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString()); } /** @@ -7023,15 +7023,25 @@ a * during the deserialization process * */ - protected void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { // Default state initialization happens here ois.defaultReadObject(); // Initialization of transient Res Bundle happens here . try { - jdbcResBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); } catch(IOException ioe) {} } static final long serialVersionUID = -3591946023893483003L; + + //------------------------- JDBC 4.1 ----------------------------------- + + public T getObject(int columnIndex, Class type) throws SQLException { + throw new SQLFeatureNotSupportedException("Not supported yet."); + } + + public T getObject(String columnLabel, Class type) throws SQLException { + throw new SQLFeatureNotSupportedException("Not supported yet."); + } } diff --git a/jdk/src/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java b/jdk/src/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java index a508904eb0d..265b44a6276 100644 --- a/jdk/src/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java +++ b/jdk/src/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,4 +153,5 @@ public class JdbcRowSetResourceBundle implements Serializable { return propResBundle.handleGetObject(key); } + static final long serialVersionUID = 436199386225359954L; } diff --git a/jdk/src/share/classes/com/sun/rowset/JoinRowSetImpl.java b/jdk/src/share/classes/com/sun/rowset/JoinRowSetImpl.java index 00f427a5eea..6963d5748f8 100644 --- a/jdk/src/share/classes/com/sun/rowset/JoinRowSetImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/JoinRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,6 +127,11 @@ public class JoinRowSetImpl extends WebRowSetImpl implements JoinRowSet { strMatchKey = null; supportedJOINs = new boolean[] {false, true, false, false, false}; + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } } @@ -4306,5 +4311,22 @@ public class JoinRowSetImpl extends WebRowSetImpl implements JoinRowSet { return crsInternal.createCopySchema(); } - static final long serialVersionUID = -5590501621560008453L; + /** + * This method re populates the resBundle + * during the deserialization process + * + */ + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Default state initialization happens here + ois.defaultReadObject(); + // Initialization of transient Res Bundle happens here . + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + + } + + static final long serialVersionUID = -5590501621560008453L; } diff --git a/jdk/src/share/classes/com/sun/rowset/RowSetFactoryImpl.java b/jdk/src/share/classes/com/sun/rowset/RowSetFactoryImpl.java new file mode 100644 index 00000000000..6f1c0fa385e --- /dev/null +++ b/jdk/src/share/classes/com/sun/rowset/RowSetFactoryImpl.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.rowset; + +import java.sql.SQLException; +import javax.sql.rowset.CachedRowSet; +import javax.sql.rowset.FilteredRowSet; +import javax.sql.rowset.JdbcRowSet; +import javax.sql.rowset.JoinRowSet; +import javax.sql.rowset.WebRowSet; +import javax.sql.rowset.RowSetFactory; + +/** + * This is the implementation specific class for the + * javax.sql.rowset.spi.RowSetFactory. This is the platform + * default implementation for the Java SE platform. + * + * @author Lance Andersen + * + * + * @version 1.7 + */ +public final class RowSetFactoryImpl implements RowSetFactory { + + public CachedRowSet createCachedRowSet() throws SQLException { + return new com.sun.rowset.CachedRowSetImpl(); + } + + public FilteredRowSet createFilteredRowSet() throws SQLException { + return new com.sun.rowset.FilteredRowSetImpl(); + } + + + public JdbcRowSet createJdbcRowSet() throws SQLException { + return new com.sun.rowset.JdbcRowSetImpl(); + } + + public JoinRowSet createJoinRowSet() throws SQLException { + return new com.sun.rowset.JoinRowSetImpl(); + } + + public WebRowSet createWebRowSet() throws SQLException { + return new com.sun.rowset.WebRowSetImpl(); + } + +} diff --git a/jdk/src/share/classes/com/sun/rowset/WebRowSetImpl.java b/jdk/src/share/classes/com/sun/rowset/WebRowSetImpl.java index 2b9e975129c..5a62c78b231 100644 --- a/jdk/src/share/classes/com/sun/rowset/WebRowSetImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/WebRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,6 +103,12 @@ public class WebRowSetImpl extends CachedRowSetImpl implements WebRowSet { */ public WebRowSetImpl(Hashtable env) throws SQLException { + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + if ( env == null) { throw new SQLException(resBundle.handleGetObject("webrowsetimpl.nullhash").toString()); } @@ -263,5 +269,23 @@ public class WebRowSetImpl extends CachedRowSetImpl implements WebRowSet { this.writeXml(oStream); } -static final long serialVersionUID = -8771775154092422943L; + + /** + * This method re populates the resBundle + * during the deserialization process + * + */ + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Default state initialization happens here + ois.defaultReadObject(); + // Initialization of transient Res Bundle happens here . + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + + } + + static final long serialVersionUID = -8771775154092422943L; } diff --git a/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetReader.java b/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetReader.java index d5b4055cc3c..31510026c47 100644 --- a/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetReader.java +++ b/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -490,4 +490,17 @@ public class CachedRowSetReader implements RowSetReader, Serializable { startPosition = pos; } + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Default state initialization happens here + ois.defaultReadObject(); + // Initialization of Res Bundle happens here . + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + + } + + static final long serialVersionUID =5049738185801363801L; } diff --git a/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java b/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java index 08ec71c0eb7..d679dad580b 100644 --- a/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java +++ b/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,13 @@ import java.util.*; import java.io.*; import com.sun.rowset.*; +import java.text.MessageFormat; import javax.sql.rowset.*; +import javax.sql.rowset.serial.SQLInputImpl; +import javax.sql.rowset.serial.SerialArray; +import javax.sql.rowset.serial.SerialBlob; +import javax.sql.rowset.serial.SerialClob; +import javax.sql.rowset.serial.SerialStruct; import javax.sql.rowset.spi.*; @@ -53,6 +59,7 @@ import javax.sql.rowset.spi.*; * Standard JDBC RowSet implementations provide an object instance of this * writer by invoking the SyncProvider.getRowSetWriter() method. * + * @version 0.2 * @author Jonathan Bruce * @see javax.sql.rowset.spi.SyncProvider * @see javax.sql.rowset.spi.SyncFactory @@ -508,10 +515,11 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable { ResultSet rs = null; rs = pstmt.executeQuery(); - if (rs.next() == true) { + ResultSetMetaData rsmd = rs.getMetaData(); + if (rs.next()) { if (rs.next()) { - /** More than one row conflict. + /** More than one row conflict. * If rs has only one row we are able to * uniquely identify the row where update * have to happen else if more than one @@ -528,7 +536,7 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable { // we require the record in rs to be used. // rs.close(); // pstmt.close(); - rs.first(); + rs.first(); // how many fields need to be updated int colsNotChanged = 0; @@ -552,6 +560,49 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable { orig = origVals.getObject(i); curr = crs.getObject(i); rsval = rs.getObject(i); + /* + * the following block creates equivalent objects + * that would have been created if this rs is populated + * into a CachedRowSet so that comparison of the column values + * from the ResultSet and CachedRowSet are possible + */ + Map map = (crs.getTypeMap() == null)?con.getTypeMap():crs.getTypeMap(); + if (rsval instanceof Struct) { + + Struct s = (Struct)rsval; + + // look up the class in the map + Class c = null; + c = (Class)map.get(s.getSQLTypeName()); + if (c != null) { + // create new instance of the class + SQLData obj = null; + try { + obj = (SQLData)c.newInstance(); + } catch (java.lang.InstantiationException ex) { + throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(), + ex.getMessage())); + } catch (java.lang.IllegalAccessException ex) { + throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(), + ex.getMessage())); + } + // get the attributes from the struct + Object attribs[] = s.getAttributes(map); + // create the SQLInput "stream" + SQLInputImpl sqlInput = new SQLInputImpl(attribs, map); + // read the values... + obj.readSQL(sqlInput, s.getSQLTypeName()); + rsval = obj; + } + } else if (rsval instanceof SQLData) { + rsval = new SerialStruct((SQLData)rsval, map); + } else if (rsval instanceof Blob) { + rsval = new SerialBlob((Blob)rsval); + } else if (rsval instanceof Clob) { + rsval = new SerialClob((Clob)rsval); + } else if (rsval instanceof java.sql.Array) { + rsval = new SerialArray((java.sql.Array)rsval, map); + } // reset boolNull if it had been set boolNull = true; @@ -669,6 +720,9 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable { } } //end for + rs.close(); + pstmt.close(); + this.crsResolve.insertRow(); this.crsResolve.moveToCurrentRow(); @@ -1179,11 +1233,22 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable { private void buildKeyDesc(CachedRowSet crs) throws SQLException { keyCols = crs.getKeyColumns(); + ResultSetMetaData resultsetmd = crs.getMetaData(); if (keyCols == null || keyCols.length == 0) { - keyCols = new int[callerColumnCount]; - for (int i = 0; i < keyCols.length; ) { - keyCols[i] = ++i; + ArrayList listKeys = new ArrayList(); + + for (int i = 0; i < callerColumnCount; i++ ) { + if(resultsetmd.getColumnType(i+1) != java.sql.Types.CLOB && + resultsetmd.getColumnType(i+1) != java.sql.Types.STRUCT && + resultsetmd.getColumnType(i+1) != java.sql.Types.SQLXML && + resultsetmd.getColumnType(i+1) != java.sql.Types.BLOB && + resultsetmd.getColumnType(i+1) != java.sql.Types.ARRAY && + resultsetmd.getColumnType(i+1) != java.sql.Types.OTHER ) + listKeys.add(i+1); } + keyCols = new int[listKeys.size()]; + for (int i = 0; i < listKeys.size(); i++ ) + keyCols[i] = listKeys.get(i); } params = new Object[keyCols.length]; } @@ -1359,4 +1424,17 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable { } } + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Default state initialization happens here + ois.defaultReadObject(); + // Initialization of Res Bundle happens here . + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + + } + + static final long serialVersionUID =-8506030970299413976L; } diff --git a/jdk/src/share/classes/com/sun/rowset/internal/InsertRow.java b/jdk/src/share/classes/com/sun/rowset/internal/InsertRow.java index f8474dc6f24..914d6fb3a51 100644 --- a/jdk/src/share/classes/com/sun/rowset/internal/InsertRow.java +++ b/jdk/src/share/classes/com/sun/rowset/internal/InsertRow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,4 +157,23 @@ public class InsertRow extends BaseRow implements Serializable, Cloneable { origVals[idx - 1] = val; markColInserted(idx - 1); } + + /** + * This method re populates the resBundle + * during the deserialization process + * + */ + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Default state initialization happens here + ois.defaultReadObject(); + // Initialization of transient Res Bundle happens here . + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + + } + + static final long serialVersionUID = 1066099658102869344L; } diff --git a/jdk/src/share/classes/com/sun/rowset/internal/SyncResolverImpl.java b/jdk/src/share/classes/com/sun/rowset/internal/SyncResolverImpl.java index 9f23cfb27a8..10573ae4d4d 100644 --- a/jdk/src/share/classes/com/sun/rowset/internal/SyncResolverImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/internal/SyncResolverImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import javax.sql.rowset.spi.*; import com.sun.rowset.*; import java.io.IOException; +import java.io.ObjectInputStream; /** * There will be two sets of data which will be maintained by the rowset at the @@ -4837,4 +4838,23 @@ public class SyncResolverImpl extends CachedRowSetImpl implements SyncResolver { throws SQLException { throw new UnsupportedOperationException("Operation not yet supported"); } + + /** + * This method re populates the resBundle + * during the deserialization process + * + */ + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Default state initialization happens here + ois.defaultReadObject(); + // Initialization of transient Res Bundle happens here . + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + + } + + static final long serialVersionUID = -3345004441725080251L; } //end class diff --git a/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java b/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java index 12a85ea77c9..a0d99e4fbcf 100644 --- a/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java +++ b/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -216,4 +216,22 @@ public class WebRowSetXmlReader implements XmlReader, Serializable { public void readData(RowSetInternal caller) { } + /** + * This method re populates the resBundle + * during the deserialization process + * + */ + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Default state initialization happens here + ois.defaultReadObject(); + // Initialization of transient Res Bundle happens here . + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + + } + + static final long serialVersionUID = -9127058392819008014L; } diff --git a/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java b/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java index 6cc6788628a..f0d59647a7f 100644 --- a/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java +++ b/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -663,4 +663,23 @@ public class WebRowSetXmlWriter implements XmlWriter, Serializable { return s; } + + /** + * This method re populates the resBundle + * during the deserialization process + * + */ + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Default state initialization happens here + ois.defaultReadObject(); + // Initialization of transient Res Bundle happens here . + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + + } + + static final long serialVersionUID = 7163134986189677641L; } diff --git a/jdk/src/share/classes/com/sun/rowset/providers/RIOptimisticProvider.java b/jdk/src/share/classes/com/sun/rowset/providers/RIOptimisticProvider.java index 545f8938f6c..5fb04167366 100644 --- a/jdk/src/share/classes/com/sun/rowset/providers/RIOptimisticProvider.java +++ b/jdk/src/share/classes/com/sun/rowset/providers/RIOptimisticProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,4 +245,18 @@ public final class RIOptimisticProvider extends SyncProvider implements Serializ public String getVendor() { return this.vendorName; } + + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Default state initialization happens here + ois.defaultReadObject(); + // Initialization of transient Res Bundle happens here . + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + + } + static final long serialVersionUID =-3143367176751761936L; + } diff --git a/jdk/src/share/classes/com/sun/security/ntlm/Client.java b/jdk/src/share/classes/com/sun/security/ntlm/Client.java new file mode 100644 index 00000000000..aed8f37084d --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/ntlm/Client.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.ntlm; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Date; +import java.util.Locale; + +/** + * The NTLM client. Not multi-thread enabled.

+ * Example: + *

+ * Client client = new Client(null, "host", "dummy",
+ *       "REALM", "t0pSeCr3t".toCharArray());
+ * byte[] type1 = client.type1();
+ * // Send type1 to server and receive response as type2
+ * byte[] type3 = client.type3(type2, nonce);
+ * // Send type3 to server
+ * 
+ */ +public final class Client extends NTLM { + final private String hostname; + final private String username; + + private String domain; // might be updated by Type 2 msg + private byte[] pw1, pw2; + + /** + * Creates an NTLM Client instance. + * @param version the NTLM version to use, which can be: + *
    + *
  • LM/NTLM: Original NTLM v1 + *
  • LM: Original NTLM v1, LM only + *
  • NTLM: Original NTLM v1, NTLM only + *
  • NTLM2: NTLM v1 with Client Challenge + *
  • LMv2/NTLMv2: NTLM v2 + *
  • LMv2: NTLM v2, LM only + *
  • NTLMv2: NTLM v2, NTLM only + *
+ * If null, "LMv2/NTLMv2" will be used. + * @param hostname hostname of the client, can be null + * @param username username to be authenticated, must not be null + * @param domain domain of {@code username}, can be null + * @param password password for {@code username}, must not be not null. + * This method does not make any modification to this parameter, it neither + * needs to access the content of this parameter after this method call, + * so you are free to modify or nullify this parameter after this call. + * @throws NullPointerException if {@code username} or {@code password} is null. + * @throws NTLMException if {@code version} is illegal + */ + public Client(String version, String hostname, String username, + String domain, char[] password) throws NTLMException { + super(version); + if ((username == null || password == null)) { + throw new NullPointerException("username/password cannot be null"); + } + this.hostname = hostname; + this.username = username; + this.domain = domain; + this.pw1 = getP1(password); + this.pw2 = getP2(password); + debug("NTLM Client: (h,u,t,version(v)) = (%s,%s,%s,%s(%s))\n", + hostname, username, domain, version, v.toString()); + } + + /** + * Generates the Type 1 message + * @return the message generated + */ + public byte[] type1() { + Writer p = new Writer(1, 32); + int flags = 0x8203; + if (hostname != null) { + flags |= 0x2000; + } + if (domain != null) { + flags |= 0x1000; + } + if (v != Version.NTLM) { + flags |= 0x80000; + } + p.writeInt(12, flags); + p.writeSecurityBuffer(24, hostname, false); + p.writeSecurityBuffer(16, domain, false); + debug("NTLM Client: Type 1 created\n"); + debug(p.getBytes()); + return p.getBytes(); + } + + /** + * Generates the Type 3 message + * @param type2 the responding Type 2 message from server, must not be null + * @param nonce random 8-byte array to be used in message generation, + * must not be null except for original NTLM v1 + * @return the message generated + * @throws NullPointerException if {@code type2} or {@code nonce} is null + * for NTLM v1. + * @throws NTLMException if the incoming message is invalid + */ + public byte[] type3(byte[] type2, byte[] nonce) throws NTLMException { + if (type2 == null || (v != Version.NTLM && nonce == null)) { + throw new NullPointerException("type2 and nonce cannot be null"); + } + debug("NTLM Client: Type 2 received\n"); + debug(type2); + Reader r = new Reader(type2); + byte[] challenge = r.readBytes(24, 8); + int inputFlags = r.readInt(20); + boolean unicode = (inputFlags & 1) == 1; + String domainFromServer = r.readSecurityBuffer(12, unicode); + if (domainFromServer != null) { + domain = domainFromServer; + } + if (domain == null) { + throw new NTLMException(NTLMException.NO_DOMAIN_INFO, + "No domain info"); + } + + int flags = 0x88200 | (inputFlags & 3); + Writer p = new Writer(3, 64); + byte[] lm = null, ntlm = null; + + p.writeSecurityBuffer(28, domain, unicode); + p.writeSecurityBuffer(36, username, unicode); + p.writeSecurityBuffer(44, hostname, unicode); + + if (v == Version.NTLM) { + byte[] lmhash = calcLMHash(pw1); + byte[] nthash = calcNTHash(pw2); + if (writeLM) lm = calcResponse (lmhash, challenge); + if (writeNTLM) ntlm = calcResponse (nthash, challenge); + } else if (v == Version.NTLM2) { + byte[] nthash = calcNTHash(pw2); + lm = ntlm2LM(nonce); + ntlm = ntlm2NTLM(nthash, nonce, challenge); + } else { + byte[] nthash = calcNTHash(pw2); + if (writeLM) lm = calcV2(nthash, + username.toUpperCase(Locale.US)+domain, nonce, challenge); + if (writeNTLM) { + byte[] alist = type2.length > 48 ? + r.readSecurityBuffer(40) : new byte[0]; + byte[] blob = new byte[32+alist.length]; + System.arraycopy(new byte[]{1,1,0,0,0,0,0,0}, 0, blob, 0, 8); + // TS + byte[] time = BigInteger.valueOf(new Date().getTime()) + .add(new BigInteger("11644473600000")) + .multiply(BigInteger.valueOf(10000)) + .toByteArray(); + for (int i=0; iSystem.out.printf(format, args)
is + * called. This method is designed to be overridden by child classes to + * match their own debugging/logging mechanisms. + * @param format a format string + * @param args the arguments referenced by format + * @see java.io.PrintStream#printf(java.lang.String, java.lang.Object[]) + */ + public void debug(String format, Object... args) { + if (DEBUG) { + System.out.printf(format, args); + } + } + + /** + * Prints out the content of a byte array, called in various places inside + * the NTLM implementation for debugging/logging purposes. When the system + * property "ntlm.debug" is set, the hexdump of the array is printed into + * System.out. This method is designed to be overridden by child classes to + * match their own debugging/logging mechanisms. + * @param bytes the byte array to print out + */ + public void debug(byte[] bytes) { + if (DEBUG) { + try { + new sun.misc.HexDumpEncoder().encodeBuffer(bytes, System.out); + } catch (IOException ioe) { + // Impossible + } + } + } + + /** + * Reading an NTLM packet + */ + static class Reader { + + private final byte[] internal; + + Reader(byte[] data) { + internal = data; + } + + int readInt(int offset) throws NTLMException { + try { + return internal[offset] & 0xff + + (internal[offset+1] & 0xff << 8) + + (internal[offset+2] & 0xff << 16) + + (internal[offset+3] & 0xff << 24); + } catch (ArrayIndexOutOfBoundsException ex) { + throw new NTLMException(NTLMException.PACKET_READ_ERROR, + "Input message incorrect size"); + } + } + + int readShort(int offset) throws NTLMException { + try { + return internal[offset] & 0xff + + (internal[offset+1] & 0xff << 8); + } catch (ArrayIndexOutOfBoundsException ex) { + throw new NTLMException(NTLMException.PACKET_READ_ERROR, + "Input message incorrect size"); + } + } + + byte[] readBytes(int offset, int len) throws NTLMException { + try { + return Arrays.copyOfRange(internal, offset, offset + len); + } catch (ArrayIndexOutOfBoundsException ex) { + throw new NTLMException(NTLMException.PACKET_READ_ERROR, + "Input message incorrect size"); + } + } + + byte[] readSecurityBuffer(int offset) throws NTLMException { + int pos = readInt(offset+4); + if (pos == 0) return null; + try { + return Arrays.copyOfRange( + internal, pos, pos + readShort(offset)); + } catch (ArrayIndexOutOfBoundsException ex) { + throw new NTLMException(NTLMException.PACKET_READ_ERROR, + "Input message incorrect size"); + } + } + + String readSecurityBuffer(int offset, boolean unicode) + throws NTLMException { + byte[] raw = readSecurityBuffer(offset); + try { + return raw == null ? null : new String( + raw, unicode ? "UnicodeLittleUnmarked" : "ISO8859_1"); + } catch (UnsupportedEncodingException ex) { + throw new NTLMException(NTLMException.PACKET_READ_ERROR, + "Invalid input encoding"); + } + } + } + + /** + * Writing an NTLM packet + */ + static class Writer { + + private byte[] internal; // buffer + private int current; // current written content interface buffer + + /** + * Starts writing a NTLM packet + * @param type NEGOTIATE || CHALLENGE || AUTHENTICATE + * @param len the base length, without security buffers + */ + Writer(int type, int len) { + assert len < 256; + internal = new byte[256]; + current = len; + System.arraycopy ( + new byte[] {'N','T','L','M','S','S','P',0,(byte)type}, + 0, internal, 0, 9); + } + + void writeShort(int offset, int number) { + internal[offset] = (byte)(number); + internal[offset+1] = (byte)(number >> 8); + } + + void writeInt(int offset, int number) { + internal[offset] = (byte)(number); + internal[offset+1] = (byte)(number >> 8); + internal[offset+2] = (byte)(number >> 16); + internal[offset+3] = (byte)(number >> 24); + } + + void writeBytes(int offset, byte[] data) { + System.arraycopy(data, 0, internal, offset, data.length); + } + + void writeSecurityBuffer(int offset, byte[] data) { + if (data == null) { + writeShort(offset+4, current); + } else { + int len = data.length; + if (current + len > internal.length) { + internal = Arrays.copyOf(internal, current + len + 256); + } + writeShort(offset, len); + writeShort(offset+2, len); + writeShort(offset+4, current); + System.arraycopy(data, 0, internal, current, len); + current += len; + } + } + + void writeSecurityBuffer(int offset, String str, boolean unicode) { + try { + writeSecurityBuffer(offset, str == null ? null : str.getBytes( + unicode ? "UnicodeLittleUnmarked" : "ISO8859_1")); + } catch (UnsupportedEncodingException ex) { + assert false; + } + } + + byte[] getBytes() { + return Arrays.copyOf(internal, current); + } + } + + // LM/NTLM + + /* Convert a 7 byte array to an 8 byte array (for a des key with parity) + * input starts at offset off + */ + byte[] makeDesKey (byte[] input, int off) { + int[] in = new int [input.length]; + for (int i=0; i> 1)); + out[2] = (byte)(((in[off+1] << 6) & 0xFF) | (in[off+2] >> 2)); + out[3] = (byte)(((in[off+2] << 5) & 0xFF) | (in[off+3] >> 3)); + out[4] = (byte)(((in[off+3] << 4) & 0xFF) | (in[off+4] >> 4)); + out[5] = (byte)(((in[off+4] << 3) & 0xFF) | (in[off+5] >> 5)); + out[6] = (byte)(((in[off+5] << 2) & 0xFF) | (in[off+6] >> 6)); + out[7] = (byte)((in[off+6] << 1) & 0xFF); + return out; + } + + byte[] calcLMHash (byte[] pwb) { + byte[] magic = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; + byte[] pwb1 = new byte [14]; + int len = pwb.length; + if (len > 14) + len = 14; + System.arraycopy (pwb, 0, pwb1, 0, len); /* Zero padded */ + + try { + DESKeySpec dks1 = new DESKeySpec (makeDesKey (pwb1, 0)); + DESKeySpec dks2 = new DESKeySpec (makeDesKey (pwb1, 7)); + + SecretKey key1 = fac.generateSecret (dks1); + SecretKey key2 = fac.generateSecret (dks2); + cipher.init (Cipher.ENCRYPT_MODE, key1); + byte[] out1 = cipher.doFinal (magic, 0, 8); + cipher.init (Cipher.ENCRYPT_MODE, key2); + byte[] out2 = cipher.doFinal (magic, 0, 8); + byte[] result = new byte [21]; + System.arraycopy (out1, 0, result, 0, 8); + System.arraycopy (out2, 0, result, 8, 8); + return result; + } catch (InvalidKeyException ive) { + // Will not happen, all key material are 8 bytes + assert false; + } catch (InvalidKeySpecException ikse) { + // Will not happen, we only feed DESKeySpec to DES factory + assert false; + } catch (IllegalBlockSizeException ibse) { + // Will not happen, we encrypt 8 bytes + assert false; + } catch (BadPaddingException bpe) { + // Will not happen, this is encryption + assert false; + } + return null; // will not happen, we returned already + } + + byte[] calcNTHash (byte[] pw) { + byte[] out = md4.digest (pw); + byte[] result = new byte [21]; + System.arraycopy (out, 0, result, 0, 16); + return result; + } + + /* key is a 21 byte array. Split it into 3 7 byte chunks, + * Convert each to 8 byte DES keys, encrypt the text arg with + * each key and return the three results in a sequential [] + */ + byte[] calcResponse (byte[] key, byte[] text) { + try { + assert key.length == 21; + DESKeySpec dks1 = new DESKeySpec(makeDesKey(key, 0)); + DESKeySpec dks2 = new DESKeySpec(makeDesKey(key, 7)); + DESKeySpec dks3 = new DESKeySpec(makeDesKey(key, 14)); + SecretKey key1 = fac.generateSecret(dks1); + SecretKey key2 = fac.generateSecret(dks2); + SecretKey key3 = fac.generateSecret(dks3); + cipher.init(Cipher.ENCRYPT_MODE, key1); + byte[] out1 = cipher.doFinal(text, 0, 8); + cipher.init(Cipher.ENCRYPT_MODE, key2); + byte[] out2 = cipher.doFinal(text, 0, 8); + cipher.init(Cipher.ENCRYPT_MODE, key3); + byte[] out3 = cipher.doFinal(text, 0, 8); + byte[] result = new byte[24]; + System.arraycopy(out1, 0, result, 0, 8); + System.arraycopy(out2, 0, result, 8, 8); + System.arraycopy(out3, 0, result, 16, 8); + return result; + } catch (IllegalBlockSizeException ex) { // None will happen + assert false; + } catch (BadPaddingException ex) { + assert false; + } catch (InvalidKeySpecException ex) { + assert false; + } catch (InvalidKeyException ex) { + assert false; + } + return null; + } + + // LMv2/NTLMv2 + + byte[] hmacMD5(byte[] key, byte[] text) { + try { + SecretKeySpec skey = + new SecretKeySpec(Arrays.copyOf(key, 16), "HmacMD5"); + hmac.init(skey); + return hmac.doFinal(text); + } catch (InvalidKeyException ex) { + assert false; + } catch (RuntimeException e) { + assert false; + } + return null; + } + + byte[] calcV2(byte[] nthash, String text, byte[] blob, byte[] challenge) { + try { + byte[] ntlmv2hash = hmacMD5(nthash, + text.getBytes("UnicodeLittleUnmarked")); + byte[] cn = new byte[blob.length+8]; + System.arraycopy(challenge, 0, cn, 0, 8); + System.arraycopy(blob, 0, cn, 8, blob.length); + byte[] result = new byte[16+blob.length]; + System.arraycopy(hmacMD5(ntlmv2hash, cn), 0, result, 0, 16); + System.arraycopy(blob, 0, result, 16, blob.length); + return result; + } catch (UnsupportedEncodingException ex) { + assert false; + } + return null; + } + + // NTLM2 LM/NTLM + + static byte[] ntlm2LM(byte[] nonce) { + return Arrays.copyOf(nonce, 24); + } + + byte[] ntlm2NTLM(byte[] ntlmHash, byte[] nonce, byte[] challenge) { + byte[] b = Arrays.copyOf(challenge, 16); + System.arraycopy(nonce, 0, b, 8, 8); + byte[] sesshash = Arrays.copyOf(md5.digest(b), 8); + return calcResponse(ntlmHash, sesshash); + } + + // Password in ASCII and UNICODE + + static byte[] getP1(char[] password) { + try { + return new String(password).toUpperCase().getBytes("ISO8859_1"); + } catch (UnsupportedEncodingException ex) { + return null; + } + } + + static byte[] getP2(char[] password) { + try { + return new String(password).getBytes("UnicodeLittleUnmarked"); + } catch (UnsupportedEncodingException ex) { + return null; + } + } +} diff --git a/jdk/src/share/classes/com/sun/security/ntlm/NTLMException.java b/jdk/src/share/classes/com/sun/security/ntlm/NTLMException.java new file mode 100644 index 00000000000..273825de8b7 --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/ntlm/NTLMException.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.ntlm; + +import java.security.GeneralSecurityException; + +/** + * An NTLM-related Exception + */ +public final class NTLMException extends GeneralSecurityException { + + /** + * If the incoming packet is invalid. + */ + public final static int PACKET_READ_ERROR = 1; + + /** + * If the client cannot get a domain value from the server and the + * caller has not provided one. + */ + public final static int NO_DOMAIN_INFO = 2; + + /** + * If the domain provided by the client does not match the one received + * from server. + */ + //public final static int DOMAIN_UNMATCH = 3; + + /** + * If the client name is not found on server's user database. + */ + public final static int USER_UNKNOWN = 3; + + /** + * If authentication fails. + */ + public final static int AUTH_FAILED = 4; + + /** + * If an illegal version string is provided. + */ + public final static int BAD_VERSION = 5; + + private int errorCode; + + /** + * Constructs an NTLMException object. + * @param errorCode the error code, which can be retrieved by + * the {@link #errorCode() } method. + * @param msg the string message, which can be retrived by + * the {@link Exception#getMessage() } method. + */ + public NTLMException(int errorCode, String msg) { + super(msg); + this.errorCode = errorCode; + } + + /** + * Returns the error code associated with this NTLMException. + * @return the error code + */ + public int errorCode() { + return errorCode; + } +} diff --git a/jdk/src/share/classes/com/sun/security/ntlm/Server.java b/jdk/src/share/classes/com/sun/security/ntlm/Server.java new file mode 100644 index 00000000000..1871375a4b7 --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/ntlm/Server.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.ntlm; + +import java.util.Arrays; +import java.util.Locale; + +/** + * The NTLM server, not multi-thread enabled.

+ * Example: + *

+ * Server server = new Server(null, "REALM") {
+ *     public char[] getPassword(String ntdomain, String username) {
+ *         switch (username) {
+ *             case "dummy": return "t0pSeCr3t".toCharArray();
+ *             case "guest": return "".toCharArray();
+ *             default: return null;
+ *         }
+ *     }
+ * };
+ * // Receive client request as type1
+ * byte[] type2 = server.type2(type1, nonce);
+ * // Send type2 to client and receive type3
+ * verify(type3, nonce);
+ * 
+ */ +public abstract class Server extends NTLM { + final private String domain; + final private boolean allVersion; + /** + * Creates a Server instance. + * @param version the NTLM version to use, which can be: + * + * If null, all versions will be supported. Please note that unless NTLM2 + * is selected, authentication succeeds if one of LM (or LMv2) or + * NTLM (or NTLMv2) is verified. + * @param domain the domain, must not be null + * @throws NullPointerException if {@code domain} is null. + */ + public Server(String version, String domain) throws NTLMException { + super(version); + if (domain == null) { + throw new NullPointerException("domain cannot be null"); + } + this.allVersion = (version == null); + this.domain = domain; + debug("NTLM Server: (t,version) = (%s,%s)\n", domain, version); + } + + /** + * Generates the Type 2 message + * @param type1 the Type1 message received, must not be null + * @param nonce the random 8-byte array to be used in message generation, + * must not be null + * @return the message generated + * @throws NullPointerException if type1 or nonce is null + * @throws NTLMException if the incoming message is invalid + */ + public byte[] type2(byte[] type1, byte[] nonce) { + if (nonce == null) { + throw new NullPointerException("nonce cannot be null"); + } + debug("NTLM Server: Type 1 received\n"); + if (type1 != null) debug(type1); + Writer p = new Writer(2, 32); + int flags = 0x80205; + p.writeSecurityBuffer(12, domain, true); + p.writeInt(20, flags); + p.writeBytes(24, nonce); + debug("NTLM Server: Type 2 created\n"); + debug(p.getBytes()); + return p.getBytes(); + } + + /** + * Verifies the Type3 message received from client and returns + * various negotiated information. + * @param type3 the incoming Type3 message from client, must not be null + * @param nonce the same nonce provided in {@link #type2}, must not be null + * @return username and hostname of the client in a byte array + * @throws NullPointerException if {@code type3} or {@code nonce} is null + * @throws NTLMException if the incoming message is invalid + */ + public String[] verify(byte[] type3, byte[] nonce) + throws NTLMException { + if (type3 == null || nonce == null) { + throw new NullPointerException("type1 or nonce cannot be null"); + } + debug("NTLM Server: Type 3 received\n"); + if (type3 != null) debug(type3); + Reader r = new Reader(type3); + String username = r.readSecurityBuffer(36, true); + String hostname = r.readSecurityBuffer(44, true); + String incomingDomain = r.readSecurityBuffer(28, true); + /*if (incomingDomain != null && !incomingDomain.equals(domain)) { + throw new NTLMException(NTLMException.DOMAIN_UNMATCH, + "Wrong domain: " + incomingDomain + + " vs " + domain); // Needed? + }*/ + boolean verified = false; + char[] password = getPassword(domain, username); + if (password == null) { + throw new NTLMException(NTLMException.USER_UNKNOWN, + "Unknown user"); + } + byte[] incomingLM = r.readSecurityBuffer(12); + byte[] incomingNTLM = r.readSecurityBuffer(20); + + if (!verified && (allVersion || v == Version.NTLM)) { + if (incomingLM.length > 0) { + byte[] pw1 = getP1(password); + byte[] lmhash = calcLMHash(pw1); + byte[] lmresponse = calcResponse (lmhash, nonce); + if (Arrays.equals(lmresponse, incomingLM)) { + verified = true; + } + } + if (incomingNTLM.length > 0) { + byte[] pw2 = getP2(password); + byte[] nthash = calcNTHash(pw2); + byte[] ntresponse = calcResponse (nthash, nonce); + if (Arrays.equals(ntresponse, incomingNTLM)) { + verified = true; + } + } + debug("NTLM Server: verify using NTLM: " + verified + "\n"); + } + if (!verified && (allVersion || v == Version.NTLM2)) { + byte[] pw2 = getP2(password); + byte[] nthash = calcNTHash(pw2); + byte[] clientNonce = Arrays.copyOf(incomingLM, 8); + byte[] ntlmresponse = ntlm2NTLM(nthash, clientNonce, nonce); + if (Arrays.equals(incomingNTLM, ntlmresponse)) { + verified = true; + } + debug("NTLM Server: verify using NTLM2: " + verified + "\n"); + } + if (!verified && (allVersion || v == Version.NTLMv2)) { + byte[] pw2 = getP2(password); + byte[] nthash = calcNTHash(pw2); + if (incomingLM.length > 0) { + byte[] clientNonce = Arrays.copyOfRange( + incomingLM, 16, incomingLM.length); + byte[] lmresponse = calcV2(nthash, + username.toUpperCase(Locale.US)+incomingDomain, + clientNonce, nonce); + if (Arrays.equals(lmresponse, incomingLM)) { + verified = true; + } + } + if (incomingNTLM.length > 0) { + byte[] clientBlob = Arrays.copyOfRange( + incomingNTLM, 16, incomingNTLM.length); + byte[] ntlmresponse = calcV2(nthash, + username.toUpperCase(Locale.US)+incomingDomain, + clientBlob, nonce); + if (Arrays.equals(ntlmresponse, incomingNTLM)) { + verified = true; + } + } + debug("NTLM Server: verify using NTLMv2: " + verified + "\n"); + } + if (!verified) { + throw new NTLMException(NTLMException.AUTH_FAILED, + "None of LM and NTLM verified"); + } + return new String[] {username, hostname}; + } + + /** + * Retrieves the password for a given user. This method should be + * overridden in a concrete class. + * @param domain can be null + * @param username must not be null + * @return the password for the user, or null if unknown + */ + public abstract char[] getPassword(String domain, String username); +} diff --git a/jdk/src/share/classes/com/sun/security/ntlm/Version.java b/jdk/src/share/classes/com/sun/security/ntlm/Version.java new file mode 100644 index 00000000000..bd4d0c4a07d --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/ntlm/Version.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.ntlm; + +enum Version { + NTLM, NTLM2, NTLMv2 +} diff --git a/jdk/src/share/classes/com/sun/security/sasl/Provider.java b/jdk/src/share/classes/com/sun/security/sasl/Provider.java index 8e43d59f357..8b9c00c8800 100644 --- a/jdk/src/share/classes/com/sun/security/sasl/Provider.java +++ b/jdk/src/share/classes/com/sun/security/sasl/Provider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,10 +35,12 @@ import java.security.PrivilegedAction; * - CRAM-MD5 * - DIGEST-MD5 * - GSSAPI/Kerberos v5 + * - NTLM * And server support for * - CRAM-MD5 * - DIGEST-MD5 * - GSSAPI/Kerberos v5 + * - NTLM */ public final class Provider extends java.security.Provider { @@ -47,8 +49,8 @@ public final class Provider extends java.security.Provider { private static final String info = "Sun SASL provider" + "(implements client mechanisms for: " + - "DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5;" + - " server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5)"; + "DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5, NTLM;" + + " server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5, NTLM)"; public Provider() { super("SunSASL", 1.7d, info); @@ -58,6 +60,8 @@ public final class Provider extends java.security.Provider { // Client mechanisms put("SaslClientFactory.DIGEST-MD5", "com.sun.security.sasl.digest.FactoryImpl"); + put("SaslClientFactory.NTLM", + "com.sun.security.sasl.ntlm.FactoryImpl"); put("SaslClientFactory.GSSAPI", "com.sun.security.sasl.gsskerb.FactoryImpl"); @@ -75,6 +79,8 @@ public final class Provider extends java.security.Provider { "com.sun.security.sasl.gsskerb.FactoryImpl"); put("SaslServerFactory.DIGEST-MD5", "com.sun.security.sasl.digest.FactoryImpl"); + put("SaslServerFactory.NTLM", + "com.sun.security.sasl.ntlm.FactoryImpl"); return null; } }); diff --git a/jdk/src/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java b/jdk/src/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java new file mode 100644 index 00000000000..6ee1b66f968 --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.sasl.ntlm; + +import java.util.Map; + +import javax.security.sasl.*; +import javax.security.auth.callback.CallbackHandler; + +import com.sun.security.sasl.util.PolicyUtils; + + +/** + * Client and server factory for NTLM SASL client/server mechanisms. + * See NTLMClient and NTLMServer for input requirements. + * + * @since 1.7 + */ + +public final class FactoryImpl implements SaslClientFactory, +SaslServerFactory{ + + private static final String myMechs[] = { "NTLM" }; + private static final int mechPolicies[] = { + PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS + }; + + /** + * Empty constructor. + */ + public FactoryImpl() { + } + + /** + * Returns a new instance of the NTLM SASL client mechanism. + * Argument checks are performed in SaslClient's constructor. + * @returns a new SaslClient ; otherwise null if unsuccessful. + * @throws SaslException If there is an error creating the NTLM + * SASL client. + */ + public SaslClient createSaslClient(String[] mechs, + String authorizationId, String protocol, String serverName, + Map props, CallbackHandler cbh) + throws SaslException { + + for (int i=0; i props, CallbackHandler cbh) + throws SaslException { + + if (mech.equals("NTLM") && + PolicyUtils.checkPolicy(mechPolicies[0], props)) { + if (props != null) { + String qop = (String)props.get(Sasl.QOP); + if (qop != null && !qop.equals("auth")) { + throw new SaslException("NTLM only support auth"); + } + } + if (cbh == null) { + throw new SaslException( + "Callback handler with support for AuthorizeCallback, "+ + "RealmCallback, NameCallback, and PasswordCallback " + + "required"); + } + return new NTLMServer(mech, protocol, serverName, props, cbh); + } + return null; + } + + /** + * Returns the authentication mechanisms that this factory can produce. + * + * @returns String[] {"NTLM"} if policies in env match those of this + * factory. + */ + public String[] getMechanismNames(Map env) { + return PolicyUtils.filterMechs(myMechs, mechPolicies, env); + } +} diff --git a/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java new file mode 100644 index 00000000000..e5746675874 --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.sasl.ntlm; + +import com.sun.security.ntlm.Client; +import com.sun.security.ntlm.NTLMException; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Map; +import java.util.Random; +import javax.security.auth.callback.Callback; + + +import javax.security.sasl.*; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +/** + * Required callbacks: + * - RealmCallback + * handle can provide domain info for authentication, optional + * - NameCallback + * handler must enter username to use for authentication + * - PasswordCallback + * handler must enter password for username to use for authentication + * + * Environment properties that affect behavior of implementation: + * + * javax.security.sasl.qop + * String, quality of protection; only "auth" is accepted, default "auth" + * + * com.sun.security.sasl.ntlm.version + * String, name a specific version to use; can be: + * LM/NTLM: Original NTLM v1 + * LM: Original NTLM v1, LM only + * NTLM: Original NTLM v1, NTLM only + * NTLM2: NTLM v1 with Client Challenge + * LMv2/NTLMv2: NTLM v2 + * LMv2: NTLM v2, LM only + * NTLMv2: NTLM v2, NTLM only + * If not specified, use system property "ntlm.version". If + * still not specified, use default value "LMv2/NTLMv2". + * + * com.sun.security.sasl.ntlm.random + * java.util.Random, the nonce source to be used in NTLM v2 or NTLM v1 with + * Client Challenge. Default null, an internal java.util.Random object + * will be used + * + * Negotiated Properties: + * + * javax.security.sasl.qop + * Always "auth" + * + * com.sun.security.sasl.html.domain + * The domain for the user, provided by the server + * + * @see RFC 2222 + * - Simple Authentication and Security Layer (SASL) + * + */ +final class NTLMClient implements SaslClient { + + private static final String NTLM_VERSION = + "com.sun.security.sasl.ntlm.version"; + private static final String NTLM_RANDOM = + "com.sun.security.sasl.ntlm.random"; + private final static String NTLM_DOMAIN = + "com.sun.security.sasl.ntlm.domain"; + private final static String NTLM_HOSTNAME = + "com.sun.security.sasl.ntlm.hostname"; + + private final Client client; + private final String mech; + private final Random random; + + private int step = 0; // 0-start,1-nego,2-auth,3-done + + /** + * @param mech non-null + * @param authorizationId can be null or empty and ignored + * @param protocol non-null for Sasl, useless for NTLM + * @param serverName non-null for Sasl, but can be null for NTLM + * @param props can be null + * @param cbh can be null for Sasl, but will throw NPE for NTLM + * @throws SaslException + */ + NTLMClient(String mech, String authzid, String protocol, String serverName, + Map props, CallbackHandler cbh) throws SaslException { + + this.mech = mech; + String version = null; + Random rtmp = null; + String hostname = null; + + if (props != null) { + String qop = (String)props.get(Sasl.QOP); + if (qop != null && !qop.equals("auth")) { + throw new SaslException("NTLM only support auth"); + } + version = (String)props.get(NTLM_VERSION); + rtmp = (Random)props.get(NTLM_RANDOM); + hostname = (String)props.get(NTLM_HOSTNAME); + } + this.random = rtmp != null ? rtmp : new Random(); + + if (version == null) { + version = System.getProperty("ntlm.version"); + } + + RealmCallback dcb = (serverName != null && !serverName.isEmpty())? + new RealmCallback("Realm: ", serverName) : + new RealmCallback("Realm: "); + NameCallback ncb = (authzid != null && !authzid.isEmpty()) ? + new NameCallback("User name: ", authzid) : + new NameCallback("User name: "); + PasswordCallback pcb = + new PasswordCallback("Password: ", false); + + try { + cbh.handle(new Callback[] {dcb, ncb, pcb}); + } catch (UnsupportedCallbackException e) { + throw new SaslException("NTLM: Cannot perform callback to " + + "acquire realm, username or password", e); + } catch (IOException e) { + throw new SaslException( + "NTLM: Error acquiring realm, username or password", e); + } + + if (hostname == null) { + try { + hostname = InetAddress.getLocalHost().getCanonicalHostName(); + } catch (UnknownHostException e) { + hostname = "localhost"; + } + } + try { + client = new Client(version, hostname, + ncb.getName(), + dcb.getText(), + pcb.getPassword()); + } catch (NTLMException ne) { + throw new SaslException( + "NTLM: Invalid version string: " + version, ne); + } + } + + @Override + public String getMechanismName() { + return mech; + } + + @Override + public boolean isComplete() { + return step >= 2; + } + + @Override + public byte[] unwrap(byte[] incoming, int offset, int len) + throws SaslException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public byte[] wrap(byte[] outgoing, int offset, int len) + throws SaslException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public Object getNegotiatedProperty(String propName) { + if (propName.equals(Sasl.QOP)) { + return "auth"; + } else if (propName.equals(NTLM_DOMAIN)) { + return client.getDomain(); + } else { + return null; + } + } + + @Override + public void dispose() throws SaslException { + client.dispose(); + } + + @Override + public boolean hasInitialResponse() { + return true; + } + + @Override + public byte[] evaluateChallenge(byte[] challenge) throws SaslException { + step++; + if (step == 1) { + return client.type1(); + } else { + try { + byte[] nonce = new byte[8]; + random.nextBytes(nonce); + return client.type3(challenge, nonce); + } catch (NTLMException ex) { + throw new SaslException("Type3 creation failed", ex); + } + } + } +} diff --git a/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java new file mode 100644 index 00000000000..7adbeb7d37e --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.sasl.ntlm; + +import com.sun.security.ntlm.NTLMException; +import com.sun.security.ntlm.Server; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Map; +import java.util.Random; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.*; + +/** + * Required callbacks: + * - RealmCallback + * used as key by handler to fetch password, optional + * - NameCallback + * used as key by handler to fetch password + * - PasswordCallback + * handler must enter password for username/realm supplied + * + * Environment properties that affect the implementation: + * + * javax.security.sasl.qop + * String, quality of protection; only "auth" is accepted, default "auth" + * + * com.sun.security.sasl.ntlm.version + * String, name a specific version to accept: + * LM/NTLM: Original NTLM v1 + * LM: Original NTLM v1, LM only + * NTLM: Original NTLM v1, NTLM only + * NTLM2: NTLM v1 with Client Challenge + * LMv2/NTLMv2: NTLM v2 + * LMv2: NTLM v2, LM only + * NTLMv2: NTLM v2, NTLM only + * If not specified, use system property "ntlm.version". If also + * not specfied, all versions are accepted. + * + * com.sun.security.sasl.ntlm.domain + * String, the domain of the server, default is server name (fqdn parameter) + * + * com.sun.security.sasl.ntlm.random + * java.util.Random, the nonce source. Default null, an internal + * java.util.Random object will be used + * + * Negotiated Properties: + * + * javax.security.sasl.qop + * Always "auth" + * + * com.sun.security.sasl.ntlm.hostname + * The hostname for the user, provided by the client + * + */ + +final class NTLMServer implements SaslServer { + + private final static String NTLM_VERSION = + "com.sun.security.sasl.ntlm.version"; + private final static String NTLM_DOMAIN = + "com.sun.security.sasl.ntlm.domain"; + private final static String NTLM_HOSTNAME = + "com.sun.security.sasl.ntlm.hostname"; + private static final String NTLM_RANDOM = + "com.sun.security.sasl.ntlm.random"; + + private final Random random; + private final Server server; + private byte[] nonce; + private int step = 0; + private String authzId; + private final String mech; + private String hostname; + + /** + * @param mech not null + * @param protocol not null for Sasl, ignored in NTLM + * @param serverName not null for Sasl, can be null in NTLM. If non-null, + * might be used as domain if not provided in props + * @param props can be null + * @param cbh can be null for Sasl, but will throw NPE in auth for NTLM + * @throws SaslException + */ + NTLMServer(String mech, String protocol, String serverName, + Map props, final CallbackHandler cbh) throws SaslException { + + this.mech = mech; + String version = null; + String domain = null; + Random rtmp = null; + + if (props != null) { + domain = (String) props.get(NTLM_DOMAIN); + version = (String)props.get(NTLM_VERSION); + rtmp = (Random)props.get(NTLM_RANDOM); + } + random = rtmp != null ? rtmp : new Random(); + + if (version == null) { + version = System.getProperty("ntlm.version"); + } + if (domain == null) { + domain = serverName; + } + if (domain == null) { + throw new NullPointerException("Domain must be provided as" + + " the serverName argument or in props"); + } + + try { + server = new Server(version, domain) { + public char[] getPassword(String ntdomain, String username) { + try { + RealmCallback rcb = new RealmCallback( + "Domain: ", ntdomain); + NameCallback ncb = new NameCallback( + "Name: ", username); + PasswordCallback pcb = new PasswordCallback( + "Password: ", false); + cbh.handle(new Callback[] { rcb, ncb, pcb }); + char[] passwd = pcb.getPassword(); + pcb.clearPassword(); + return passwd; + } catch (IOException ioe) { + return null; + } catch (UnsupportedCallbackException uce) { + return null; + } + } + }; + } catch (NTLMException ne) { + throw new SaslException( + "NTLM: Invalid version string: " + version, ne); + } + nonce = new byte[8]; + } + + @Override + public String getMechanismName() { + return mech; + } + + @Override + public byte[] evaluateResponse(byte[] response) throws SaslException { + try { + step++; + if (step == 1) { + random.nextBytes(nonce); + return server.type2(response, nonce); + } else { + String[] out = server.verify(response, nonce); + authzId = out[0]; + hostname = out[1]; + return null; + } + } catch (GeneralSecurityException ex) { + throw new SaslException("", ex); + } + } + + @Override + public boolean isComplete() { + return step >= 2; + } + + @Override + public String getAuthorizationID() { + return authzId; + } + + @Override + public byte[] unwrap(byte[] incoming, int offset, int len) + throws SaslException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public byte[] wrap(byte[] outgoing, int offset, int len) + throws SaslException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getNegotiatedProperty(String propName) { + if (propName.equals(Sasl.QOP)) { + return "auth"; + } else if (propName.equals(NTLM_HOSTNAME)) { + return hostname; + } else { + return null; + } + } + + @Override + public void dispose() throws SaslException { + return; + } +} diff --git a/jdk/src/share/classes/java/awt/Dialog.java b/jdk/src/share/classes/java/awt/Dialog.java index 71b08d7226d..3e2effd1dc0 100644 --- a/jdk/src/share/classes/java/awt/Dialog.java +++ b/jdk/src/share/classes/java/awt/Dialog.java @@ -277,10 +277,8 @@ public class Dialog extends Window { */ String title; - private transient volatile boolean keepBlockingEDT = false; - private transient volatile boolean keepBlockingCT = false; - private transient ModalEventFilter modalFilter; + private transient volatile SecondaryLoop secondaryLoop; /* * Indicates that this dialog is being hidden. This flag is set to true at @@ -1005,12 +1003,6 @@ public class Dialog extends Window { super.setVisible(b); } - /** - * Stores the app context on which event dispatch thread the dialog - * is being shown. Initialized in show(), used in hideAndDisposeHandler() - */ - transient private AppContext showAppContext; - /** * Makes the {@code Dialog} visible. If the dialog and/or its owner * are not yet displayable, both are made displayable. The @@ -1037,39 +1029,18 @@ public class Dialog extends Window { if (!isModal()) { conditionalShow(null, null); } else { - // Set this variable before calling conditionalShow(). That - // way, if the Dialog is hidden right after being shown, we - // won't mistakenly block this thread. - keepBlockingEDT = true; - keepBlockingCT = true; - - // Store the app context on which this dialog is being shown. - // Event dispatch thread of this app context will be sleeping until - // we wake it by any event from hideAndDisposeHandler(). - showAppContext = AppContext.getAppContext(); + AppContext showAppContext = AppContext.getAppContext(); AtomicLong time = new AtomicLong(); Component predictedFocusOwner = null; try { predictedFocusOwner = getMostRecentFocusOwner(); if (conditionalShow(predictedFocusOwner, time)) { - // We have two mechanisms for blocking: 1. If we're on the - // EventDispatchThread, start a new event pump. 2. If we're - // on any other thread, call wait() on the treelock. - modalFilter = ModalEventFilter.createFilterForDialog(this); - - final Runnable pumpEventsForFilter = new Runnable() { - public void run() { - EventDispatchThread dispatchThread = - (EventDispatchThread)Thread.currentThread(); - dispatchThread.pumpEventsForFilter(new Conditional() { - public boolean evaluate() { - synchronized (getTreeLock()) { - return keepBlockingEDT && windowClosingException == null; - } - } - }, modalFilter); + Conditional cond = new Conditional() { + @Override + public boolean evaluate() { + return windowClosingException == null; } }; @@ -1096,44 +1067,10 @@ public class Dialog extends Window { modalityPushed(); try { - if (EventQueue.isDispatchThread()) { - /* - * dispose SequencedEvent we are dispatching on current - * AppContext, to prevent us from hang. - * - */ - // BugId 4531693 (son@sparc.spb.su) - SequencedEvent currentSequencedEvent = KeyboardFocusManager. - getCurrentKeyboardFocusManager().getCurrentSequencedEvent(); - if (currentSequencedEvent != null) { - currentSequencedEvent.dispose(); - } - - /* - * Event processing is done inside doPrivileged block so that - * it wouldn't matter even if user code is on the stack - * Fix for BugId 6300270 - */ - - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - pumpEventsForFilter.run(); - return null; - } - }); - } else { - synchronized (getTreeLock()) { - Toolkit.getEventQueue().postEvent(new PeerEvent(this, - pumpEventsForFilter, - PeerEvent.PRIORITY_EVENT)); - while (keepBlockingCT && windowClosingException == null) { - try { - getTreeLock().wait(); - } catch (InterruptedException e) { - break; - } - } - } + EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); + secondaryLoop = eventQueue.createSecondaryLoop(cond, modalFilter, 5000); + if (!secondaryLoop.enter()) { + secondaryLoop = null; } } finally { modalityPopped(); @@ -1194,18 +1131,11 @@ public class Dialog extends Window { windowClosingException = null; } } - final class WakingRunnable implements Runnable { - public void run() { - synchronized (getTreeLock()) { - keepBlockingCT = false; - getTreeLock().notifyAll(); - } - } - } + private void hideAndDisposePreHandler() { isInHide = true; synchronized (getTreeLock()) { - if (keepBlockingEDT) { + if (secondaryLoop != null) { modalHide(); // dialog can be shown and then disposed before its // modal filter is created @@ -1217,20 +1147,9 @@ public class Dialog extends Window { } } private void hideAndDisposeHandler() { - synchronized (getTreeLock()) { - if (keepBlockingEDT) { - keepBlockingEDT = false; - PeerEvent wakingEvent = new PeerEvent(getToolkit(), new WakingRunnable(), PeerEvent.PRIORITY_EVENT); - AppContext curAppContext = AppContext.getAppContext(); - if (showAppContext != curAppContext) { - // Wake up event dispatch thread on which the dialog was - // initially shown - SunToolkit.postEvent(showAppContext, wakingEvent); - showAppContext = null; - } else { - Toolkit.getEventQueue().postEvent(wakingEvent); - } - } + if (secondaryLoop != null) { + secondaryLoop.exit(); + secondaryLoop = null; } isInHide = false; } diff --git a/jdk/src/share/classes/java/awt/EventDispatchThread.java b/jdk/src/share/classes/java/awt/EventDispatchThread.java index eed2c16e514..b47c3686e81 100644 --- a/jdk/src/share/classes/java/awt/EventDispatchThread.java +++ b/jdk/src/share/classes/java/awt/EventDispatchThread.java @@ -113,8 +113,7 @@ class EventDispatchThread extends Thread { pumpEventsForHierarchy(id, cond, null); } - void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) - { + void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) { pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent)); } @@ -124,6 +123,7 @@ class EventDispatchThread extends Thread { void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) { addEventFilter(filter); + doDispatch = true; while (doDispatch && cond.evaluate()) { if (isInterrupted() || !pumpOneEventForFilters(id)) { doDispatch = false; @@ -133,6 +133,7 @@ class EventDispatchThread extends Thread { } void addEventFilter(EventFilter filter) { + eventLog.finest("adding the event filter: " + filter); synchronized (eventFilters) { if (!eventFilters.contains(filter)) { if (filter instanceof ModalEventFilter) { @@ -156,6 +157,7 @@ class EventDispatchThread extends Thread { } void removeEventFilter(EventFilter filter) { + eventLog.finest("removing the event filter: " + filter); synchronized (eventFilters) { eventFilters.remove(filter); } diff --git a/jdk/src/share/classes/java/awt/EventQueue.java b/jdk/src/share/classes/java/awt/EventQueue.java index 86c68e8b5c7..ffda53b69e7 100644 --- a/jdk/src/share/classes/java/awt/EventQueue.java +++ b/jdk/src/share/classes/java/awt/EventQueue.java @@ -883,6 +883,41 @@ public class EventQueue { } } + /** + * Creates a new {@code secondary loop} associated with this + * event queue. Use the {@link SecondaryLoop#enter} and + * {@link SecondaryLoop#exit} methods to start and stop the + * event loop and dispatch the events from this queue. + * + * @return secondaryLoop A new secondary loop object, which can + * be used to launch a new nested event + * loop and dispatch events from this queue + * + * @see SecondaryLoop#enter + * @see SecondaryLoop#exit + * + * @since 1.7 + */ + public SecondaryLoop createSecondaryLoop() { + return createSecondaryLoop(null, null, 0); + } + + SecondaryLoop createSecondaryLoop(Conditional cond, EventFilter filter, long interval) { + pushPopLock.lock(); + try { + if (nextQueue != null) { + // Forward the request to the top of EventQueue stack + return nextQueue.createSecondaryLoop(cond, filter, interval); + } + if (dispatchThread == null) { + initDispatchThread(); + } + return new WaitDispatchSupport(dispatchThread, cond, filter, interval); + } finally { + pushPopLock.unlock(); + } + } + /** * Returns true if the calling thread is * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s diff --git a/jdk/src/share/classes/java/awt/SecondaryLoop.java b/jdk/src/share/classes/java/awt/SecondaryLoop.java new file mode 100644 index 00000000000..844efc85261 --- /dev/null +++ b/jdk/src/share/classes/java/awt/SecondaryLoop.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt; + +/** + * A helper interface to run the nested event loop. + *

+ * Objects that implement this interface are created with the + * {@link EventQueue#createSecondaryLoop} method. The interface + * provides two methods, {@link enter} and {@link exit}, + * which can be used to start and stop the event loop. + *

+ * When the {@link enter} method is called, the current + * thread is blocked until the loop is terminated by the + * {@link exit} method. Also, a new event loop is started + * on the event dispatch thread, which may or may not be + * the current thread. The loop can be terminated on any + * thread by calling its {@link exit} method. After the + * loop is terminated, the {@code SecondaryLoop} object can + * be reused to run a new nested event loop. + *

+ * A typical use case of applying this interface is AWT + * and Swing modal dialogs. When a modal dialog is shown on + * the event dispatch thread, it enters a new secondary loop. + * Later, when the dialog is hidden or disposed, it exits + * the loop, and the thread continues its execution. + *

+ * The following example illustrates a simple use case of + * secondary loops: + * + *

+ *   SecondaryLoop loop;
+ *
+ *   JButton jButton = new JButton("Button");
+ *   jButton.addActionListener(new ActionListener() {
+ *       {@code @Override}
+ *       public void actionPerformed(ActionEvent e) {
+ *           Toolkit tk = Toolkit.getDefaultToolkit();
+ *           EventQueue eq = tk.getSystemEventQueue();
+ *           loop = eq.createSecondaryLoop();
+ *
+ *           // Spawn a new thread to do the work
+ *           Thread worker = new WorkerThread();
+ *           worker.start();
+ *
+ *           // Enter the loop to block the current event
+ *           // handler, but leave UI responsive
+ *           if (!loop.enter()) {
+ *               // Report an error
+ *           }
+ *       }
+ *   });
+ *
+ *   class WorkerThread extends Thread {
+ *       {@code @Override}
+ *       public void run() {
+ *           // Perform calculations
+ *           doSomethingUseful();
+ *
+ *           // Exit the loop
+ *           loop.exit();
+ *       }
+ *   }
+ * 
+ * + * @see Dialog#show + * @see EventQueue#createSecondaryLoop + * @see Toolkit#getSystemEventQueue + * + * @author Anton Tarasov, Artem Ananiev + * + * @since 1.7 + */ +public interface SecondaryLoop { + + /** + * Blocks the execution of the current thread and enters a new + * secondary event loop on the event dispatch thread. + *

+ * This method can be called by any thread including the event + * dispatch thread. This thread will be blocked until the {@link + * exit} method is called or the loop is terminated. A new + * secondary loop will be created on the event dispatch thread + * for dispatching events in either case. + *

+ * This method can only start one new event loop at a time per + * object. If a secondary event loop has already been started + * by this object and is currently still running, this method + * returns {@code false} to indicate that it was not successful + * in starting a new event loop. Otherwise, this method blocks + * the calling thread and later returns {@code true} when the + * new event loop is terminated. At such time, this object can + * again be used to start another new event loop. + * + * @return {@code true} after termination of the secondary loop, + * if the secondary loop was started by this call, + * {@code false} otherwise + */ + public boolean enter(); + + /** + * Unblocks the execution of the thread blocked by the {@link + * enter} method and exits the secondary loop. + *

+ * This method resumes the thread that called the {@link enter} + * method and exits the secondary loop that was created when + * the {@link enter} method was invoked. + *

+ * Note that if any other secondary loop is started while this + * loop is running, the blocked thread will not resume execution + * until the nested loop is terminated. + *

+ * If this secondary loop has not been started with the {@link + * enter} method, or this secondary loop has already finished + * with the {@link exit} method, this method returns {@code + * false}, otherwise {@code true} is returned. + * + * @return {@code true} if this loop was previously started and + * has not yet been finished with the {@link exit} method, + * {@code false} otherwise + */ + public boolean exit(); + +} diff --git a/jdk/src/share/classes/java/awt/WaitDispatchSupport.java b/jdk/src/share/classes/java/awt/WaitDispatchSupport.java new file mode 100644 index 00000000000..bf77fa73a62 --- /dev/null +++ b/jdk/src/share/classes/java/awt/WaitDispatchSupport.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicBoolean; + +import java.security.PrivilegedAction; +import java.security.AccessController; + +import sun.awt.PeerEvent; + +import sun.util.logging.PlatformLogger; + +/** + * This utility class is used to suspend execution on a thread + * while still allowing {@code EventDispatchThread} to dispatch events. + * The API methods of the class are thread-safe. + * + * @author Anton Tarasov, Artem Ananiev + * + * @since 1.7 + */ +class WaitDispatchSupport implements SecondaryLoop { + + private final static PlatformLogger log = + PlatformLogger.getLogger("java.awt.event.WaitDispatchSupport"); + + private EventDispatchThread dispatchThread; + private EventFilter filter; + + private volatile Conditional extCondition; + private volatile Conditional condition; + + private long interval; + // Use a shared daemon timer to serve all the WaitDispatchSupports + private static Timer timer; + // When this WDS expires, we cancel the timer task leaving the + // shared timer up and running + private TimerTask timerTask; + + private AtomicBoolean keepBlockingEDT = new AtomicBoolean(false); + private AtomicBoolean keepBlockingCT = new AtomicBoolean(false); + + private static synchronized void initializeTimer() { + if (timer == null) { + timer = new Timer("AWT-WaitDispatchSupport-Timer", true); + } + } + + /** + * Creates a {@code WaitDispatchSupport} instance to + * serve the given event dispatch thread. + * + * @param dispatchThread An event dispatch thread that + * should not stop dispatching events while waiting + * + * @since 1.7 + */ + public WaitDispatchSupport(EventDispatchThread dispatchThread) { + this(dispatchThread, null); + } + + /** + * Creates a {@code WaitDispatchSupport} instance to + * serve the given event dispatch thread. + * + * @param dispatchThread An event dispatch thread that + * should not stop dispatching events while waiting + * @param extCondition A conditional object used to determine + * if the loop should be terminated + * + * @since 1.7 + */ + public WaitDispatchSupport(EventDispatchThread dispatchThread, + Conditional extCond) + { + if (dispatchThread == null) { + throw new IllegalArgumentException("The dispatchThread can not be null"); + } + + this.dispatchThread = dispatchThread; + this.extCondition = extCond; + this.condition = new Conditional() { + @Override + public boolean evaluate() { + if (log.isLoggable(PlatformLogger.FINEST)) { + log.finest("evaluate(): blockingEDT=" + keepBlockingEDT.get() + + ", blockingCT=" + keepBlockingCT.get()); + } + boolean extEvaluate = + (extCondition != null) ? extCondition.evaluate() : true; + if (!keepBlockingEDT.get() || !extEvaluate) { + if (timerTask != null) { + timerTask.cancel(); + timerTask = null; + } + return false; + } + return true; + } + }; + } + + /** + * Creates a {@code WaitDispatchSupport} instance to + * serve the given event dispatch thread. + *

+ * The {@link EventFilter} is set on the {@code dispatchThread} + * while waiting. The filter is removed on completion of the + * waiting process. + *

+ * + * + * @param dispatchThread An event dispatch thread that + * should not stop dispatching events while waiting + * @param filter {@code EventFilter} to be set + * @param interval A time interval to wait for. Note that + * when the waiting process takes place on EDT + * there is no guarantee to stop it in the given time + * + * @since 1.7 + */ + public WaitDispatchSupport(EventDispatchThread dispatchThread, + Conditional extCondition, + EventFilter filter, long interval) + { + this(dispatchThread, extCondition); + this.filter = filter; + if (interval < 0) { + throw new IllegalArgumentException("The interval value must be >= 0"); + } + this.interval = interval; + if (interval != 0) { + initializeTimer(); + } + } + + /** + * @inheritDoc + */ + @Override + public boolean enter() { + log.fine("enter(): blockingEDT=" + keepBlockingEDT.get() + + ", blockingCT=" + keepBlockingCT.get()); + + if (!keepBlockingEDT.compareAndSet(false, true)) { + log.fine("The secondary loop is already running, aborting"); + return false; + } + + final Runnable run = new Runnable() { + public void run() { + log.fine("Starting a new event pump"); + if (filter == null) { + dispatchThread.pumpEvents(condition); + } else { + dispatchThread.pumpEventsForFilter(condition, filter); + } + } + }; + + // We have two mechanisms for blocking: if we're on the + // dispatch thread, start a new event pump; if we're + // on any other thread, call wait() on the treelock + + Thread currentThread = Thread.currentThread(); + if (currentThread == dispatchThread) { + log.finest("On dispatch thread: " + dispatchThread); + if (interval != 0) { + log.finest("scheduling the timer for " + interval + " ms"); + timer.schedule(timerTask = new TimerTask() { + @Override + public void run() { + if (keepBlockingEDT.compareAndSet(true, false)) { + wakeupEDT(); + } + } + }, interval); + } + // Dispose SequencedEvent we are dispatching on the the current + // AppContext, to prevent us from hang - see 4531693 for details + SequencedEvent currentSE = KeyboardFocusManager. + getCurrentKeyboardFocusManager().getCurrentSequencedEvent(); + if (currentSE != null) { + log.fine("Dispose current SequencedEvent: " + currentSE); + currentSE.dispose(); + } + // In case the exit() method is called before starting + // new event pump it will post the waking event to EDT. + // The event will be handled after the the new event pump + // starts. Thus, the enter() method will not hang. + // + // Event pump should be privileged. See 6300270. + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + run.run(); + return null; + } + }); + } else { + log.finest("On non-dispatch thread: " + currentThread); + synchronized (getTreeLock()) { + if (filter != null) { + dispatchThread.addEventFilter(filter); + } + try { + EventQueue eq = dispatchThread.getEventQueue(); + eq.postEvent(new PeerEvent(this, run, PeerEvent.PRIORITY_EVENT)); + keepBlockingCT.set(true); + if (interval > 0) { + long currTime = System.currentTimeMillis(); + while (keepBlockingCT.get() && + ((extCondition != null) ? extCondition.evaluate() : true) && + (currTime + interval > System.currentTimeMillis())) + { + getTreeLock().wait(interval); + } + } else { + while (keepBlockingCT.get() && + ((extCondition != null) ? extCondition.evaluate() : true)) + { + getTreeLock().wait(); + } + } + log.fine("waitDone " + keepBlockingEDT.get() + " " + keepBlockingCT.get()); + } catch (InterruptedException e) { + log.fine("Exception caught while waiting: " + e); + } finally { + if (filter != null) { + dispatchThread.removeEventFilter(filter); + } + } + // If the waiting process has been stopped because of the + // time interval passed or an exception occurred, the state + // should be changed + keepBlockingEDT.set(false); + keepBlockingCT.set(false); + } + } + + return true; + } + + /** + * @inheritDoc + */ + public boolean exit() { + log.fine("exit(): blockingEDT=" + keepBlockingEDT.get() + + ", blockingCT=" + keepBlockingCT.get()); + if (keepBlockingEDT.compareAndSet(true, false)) { + wakeupEDT(); + return true; + } + return false; + } + + private final static Object getTreeLock() { + return Component.LOCK; + } + + private final Runnable wakingRunnable = new Runnable() { + public void run() { + log.fine("Wake up EDT"); + synchronized (getTreeLock()) { + keepBlockingCT.set(false); + getTreeLock().notifyAll(); + } + log.fine("Wake up EDT done"); + } + }; + + private void wakeupEDT() { + log.finest("wakeupEDT(): EDT == " + dispatchThread); + EventQueue eq = dispatchThread.getEventQueue(); + eq.postEvent(new PeerEvent(this, wakingRunnable, PeerEvent.PRIORITY_EVENT)); + } +} diff --git a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java index fad8ad6da66..46a14a0aa20 100644 --- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java +++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java @@ -470,7 +470,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { public AbstractStringBuilder append(CharSequence s, int start, int end) { if (s == null) s = "null"; - if ((start < 0) || (end < 0) || (start > end) || (end > s.length())) + if ((start < 0) || (start > end) || (end > s.length())) throw new IndexOutOfBoundsException( "start " + start + ", end " + end + ", s.length() " + s.length()); @@ -529,7 +529,8 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * or {@code offset+len > str.length} */ public AbstractStringBuilder append(char str[], int offset, int len) { - ensureCapacityInternal(count + len); + if (len > 0) // let arraycopy report AIOOBE for len < 0 + ensureCapacityInternal(count + len); System.arraycopy(str, offset, value, count, len); count += len; return this; diff --git a/jdk/src/share/classes/java/lang/AutoCloseable.java b/jdk/src/share/classes/java/lang/AutoCloseable.java index 18c28fe887b..a44f5840cd7 100644 --- a/jdk/src/share/classes/java/lang/AutoCloseable.java +++ b/jdk/src/share/classes/java/lang/AutoCloseable.java @@ -34,8 +34,8 @@ package java.lang; public interface AutoCloseable { /** * Close this resource, relinquishing any underlying resources. - * This method is invoked automatically by the automatic resource - * management block construct. + * This method is invoked automatically by the {@code + * try}-with-resources statement. * *

Classes implementing this method are strongly encouraged to * be declared to throw more specific exceptions (or no exception diff --git a/jdk/src/share/classes/java/lang/Character.java b/jdk/src/share/classes/java/lang/Character.java index 69134bda77f..0a64916d3bf 100644 --- a/jdk/src/share/classes/java/lang/Character.java +++ b/jdk/src/share/classes/java/lang/Character.java @@ -595,7 +595,6 @@ class Character implements java.io.Serializable, Comparable { /** * Constructs a new Subset instance. * - * @exception NullPointerException if name is null * @param name The name of this subset * @exception NullPointerException if name is null */ diff --git a/jdk/src/share/classes/java/lang/CharacterName.java b/jdk/src/share/classes/java/lang/CharacterName.java index d097340871d..cac053b10e8 100644 --- a/jdk/src/share/classes/java/lang/CharacterName.java +++ b/jdk/src/share/classes/java/lang/CharacterName.java @@ -1,12 +1,12 @@ /* - * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this + * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -18,9 +18,9 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. */ package java.lang; diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java index d3346417c0f..fd9ba91d720 100644 --- a/jdk/src/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/share/classes/java/lang/ClassLoader.java @@ -823,7 +823,7 @@ public abstract class ClassLoader { * * * @param name - * The expected binary namebinary name. of the class, or * null if not known * * @param b diff --git a/jdk/src/share/classes/java/lang/Object.java b/jdk/src/share/classes/java/lang/Object.java index 2e1011a60da..c730db44e23 100644 --- a/jdk/src/share/classes/java/lang/Object.java +++ b/jdk/src/share/classes/java/lang/Object.java @@ -189,7 +189,9 @@ public class Object { * specific cloning operation. First, if the class of this object does * not implement the interface {@code Cloneable}, then a * {@code CloneNotSupportedException} is thrown. Note that all arrays - * are considered to implement the interface {@code Cloneable}. + * are considered to implement the interface {@code Cloneable} and that + * the return type of the {@code clone} method of an array type {@code T[]} + * is {@code T[]} where T is any reference or primitive type. * Otherwise, this method creates a new instance of the class of this * object and initializes all its fields with exactly the contents of * the corresponding fields of this object, as if by assignment; the diff --git a/jdk/src/share/classes/java/lang/Thread.java b/jdk/src/share/classes/java/lang/Thread.java index c379ec59135..c3592cf5cf3 100644 --- a/jdk/src/share/classes/java/lang/Thread.java +++ b/jdk/src/share/classes/java/lang/Thread.java @@ -413,6 +413,18 @@ class Thread implements Runnable { tid = nextThreadID(); } + /** + * Throws CloneNotSupportedException as a Thread can not be meaningfully + * cloned. Construct a new Thread instead. + * + * @throws CloneNotSupportedException + * always + */ + @Override + protected Object clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + /** * Allocates a new {@code Thread} object. This constructor has the same * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} diff --git a/jdk/src/share/classes/java/lang/Throwable.java b/jdk/src/share/classes/java/lang/Throwable.java index 213f5f86d5c..0073d3f3c3d 100644 --- a/jdk/src/share/classes/java/lang/Throwable.java +++ b/jdk/src/share/classes/java/lang/Throwable.java @@ -200,7 +200,16 @@ public class Throwable implements Serializable { * @serial * @since 1.7 */ - private List suppressedExceptions = Collections.emptyList(); + private List suppressedExceptions = null; + /* + * This field is lazily initialized when the first suppressed + * exception is added. + * + * OutOfMemoryError is preallocated in the VM for better OOM + * diagnosability during VM initialization. Constructor can't + * be not invoked. If a new field to be added in the future must + * be initialized to non-null, it requires a synchronized VM change. + */ /** Message for trying to suppress a null exception. */ private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception."; @@ -329,7 +338,7 @@ public class Throwable implements Serializable { * cause is nonexistent or unknown. * @since 1.4 */ - public Throwable getCause() { + public synchronized Throwable getCause() { return (cause==this ? null : cause); } @@ -489,8 +498,8 @@ public class Throwable implements Serializable { * } * * As of release 7, the platform supports the notion of - * suppressed exceptions (in conjunction with automatic - * resource management blocks). Any exceptions that were + * suppressed exceptions (in conjunction with the {@code + * try}-with-resources statement). Any exceptions that were * suppressed in order to deliver an exception are printed out * beneath the stack trace. The format of this information * depends on the implementation, but the following example may be @@ -563,7 +572,7 @@ public class Throwable implements Serializable { s.println("\tat " + traceElement); // Print suppressed exceptions, if any - for (Throwable se : suppressedExceptions) + for (Throwable se : getSuppressedExceptions()) se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu); // Print cause, if any @@ -604,7 +613,7 @@ public class Throwable implements Serializable { s.println(prefix + "\t... " + framesInCommon + " more"); // Print suppressed exceptions, if any - for (Throwable se : suppressedExceptions) + for (Throwable se : getSuppressedExceptions()) se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, prefix +"\t", dejaVu); @@ -747,7 +756,9 @@ public class Throwable implements Serializable { if (defensiveCopy[i] == null) throw new NullPointerException("stackTrace[" + i + "]"); - this.stackTrace = defensiveCopy; + synchronized (this) { + this.stackTrace = defensiveCopy; + } } /** @@ -772,11 +783,11 @@ public class Throwable implements Serializable { private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); // read in all fields - List suppressed = Collections.emptyList(); + List suppressed = null; if (suppressedExceptions != null && !suppressedExceptions.isEmpty()) { // Copy Throwables to new list suppressed = new ArrayList(); - for(Throwable t : suppressedExceptions) { + for (Throwable t : suppressedExceptions) { if (t == null) throw new NullPointerException(NULL_CAUSE_MESSAGE); suppressed.add(t); @@ -794,7 +805,7 @@ public class Throwable implements Serializable { /** * Adds the specified exception to the list of exceptions that - * were suppressed, typically by the automatic resource management + * were suppressed, typically by the {@code try}-with-resources * statement, in order to deliver this exception. * *

Note that when one exception {@linkplain @@ -819,7 +830,7 @@ public class Throwable implements Serializable { if (exception == this) throw new IllegalArgumentException("Self-suppression not permitted"); - if (suppressedExceptions.size() == 0) + if (suppressedExceptions == null) suppressedExceptions = new ArrayList(); suppressedExceptions.add(exception); } @@ -828,14 +839,17 @@ public class Throwable implements Serializable { /** * Returns an array containing all of the exceptions that were - * suppressed, typically by the automatic resource management + * suppressed, typically by the {@code try}-with-resources * statement, in order to deliver this exception. * * @return an array containing all of the exceptions that were * suppressed to deliver this exception. * @since 1.7 */ - public Throwable[] getSuppressedExceptions() { - return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); + public synchronized Throwable[] getSuppressedExceptions() { + if (suppressedExceptions == null) + return EMPTY_THROWABLE_ARRAY; + else + return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); } } diff --git a/jdk/src/share/classes/java/lang/reflect/Constructor.java b/jdk/src/share/classes/java/lang/reflect/Constructor.java index 6515eb282d9..e4b808e41bf 100644 --- a/jdk/src/share/classes/java/lang/reflect/Constructor.java +++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java @@ -166,8 +166,7 @@ public final /** * Returns the name of this constructor, as a string. This is - * always the same as the simple name of the constructor's declaring - * class. + * the binary name of the constructor's declaring class. */ public String getName() { return getDeclaringClass().getName(); diff --git a/jdk/src/share/classes/java/net/HttpCookie.java b/jdk/src/share/classes/java/net/HttpCookie.java index 5b00869ab95..07d9cee3e8a 100644 --- a/jdk/src/share/classes/java/net/HttpCookie.java +++ b/jdk/src/share/classes/java/net/HttpCookie.java @@ -1093,14 +1093,8 @@ public final class HttpCookie implements Cloneable { return sb.toString(); } - private static SimpleDateFormat[] cDateFormats = null; - static { - cDateFormats = new SimpleDateFormat[COOKIE_DATE_FORMATS.length]; - for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) { - cDateFormats[i] = new SimpleDateFormat(COOKIE_DATE_FORMATS[i], Locale.US); - cDateFormats[i].setTimeZone(TimeZone.getTimeZone("GMT")); - } - } + static final TimeZone GMT = TimeZone.getTimeZone("GMT"); + /* * @param dateString a date string in one of the formats * defined in Netscape cookie spec @@ -1109,12 +1103,14 @@ public final class HttpCookie implements Cloneable { * time and the time specified by dateString */ private long expiryDate2DeltaSeconds(String dateString) { - for (SimpleDateFormat df : cDateFormats) { + for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) { + SimpleDateFormat df = new SimpleDateFormat(COOKIE_DATE_FORMATS[i], Locale.US); + df.setTimeZone(GMT); try { Date date = df.parse(dateString); return (date.getTime() - whenCreated) / 1000; } catch (Exception e) { - + // Ignore, try the next date format } } return 0; diff --git a/jdk/src/share/classes/java/net/SdpSocketImpl.java b/jdk/src/share/classes/java/net/SdpSocketImpl.java new file mode 100644 index 00000000000..b5b023e2433 --- /dev/null +++ b/jdk/src/share/classes/java/net/SdpSocketImpl.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.net; + +import java.io.IOException; +import java.io.FileDescriptor; + +import sun.net.sdp.SdpSupport; + +/** + * SocketImpl that supports the SDP protocol + */ +class SdpSocketImpl extends PlainSocketImpl { + SdpSocketImpl() { } + + @Override + protected void create(boolean stream) throws IOException { + if (!stream) + throw new UnsupportedOperationException("Must be a stream socket"); + fd = SdpSupport.createSocket(); + if (socket != null) + socket.setCreated(); + if (serverSocket != null) + serverSocket.setCreated(); + } +} diff --git a/jdk/src/share/classes/java/net/ServerSocket.java b/jdk/src/share/classes/java/net/ServerSocket.java index 8189d8aa4f0..d4b44e4ccb2 100644 --- a/jdk/src/share/classes/java/net/ServerSocket.java +++ b/jdk/src/share/classes/java/net/ServerSocket.java @@ -68,6 +68,15 @@ class ServerSocket implements java.io.Closeable { */ private boolean oldImpl = false; + /** + * Package-private constructor to create a ServerSocket associated with + * the given SocketImpl. + */ + ServerSocket(SocketImpl impl) { + this.impl = impl; + impl.setServerSocket(this); + } + /** * Creates an unbound server socket. * diff --git a/jdk/src/share/classes/java/net/URI.java b/jdk/src/share/classes/java/net/URI.java index c05b7b2abaa..9b891b4b4dd 100644 --- a/jdk/src/share/classes/java/net/URI.java +++ b/jdk/src/share/classes/java/net/URI.java @@ -856,9 +856,7 @@ public final class URI try { return new URI(str); } catch (URISyntaxException x) { - IllegalArgumentException y = new IllegalArgumentException(); - y.initCause(x); - throw y; + throw new IllegalArgumentException(x.getMessage(), x); } } diff --git a/jdk/src/share/classes/java/nio/file/DirectoryIteratorException.java b/jdk/src/share/classes/java/nio/file/DirectoryIteratorException.java new file mode 100644 index 00000000000..729c84a77cd --- /dev/null +++ b/jdk/src/share/classes/java/nio/file/DirectoryIteratorException.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.nio.file; + +import java.util.ConcurrentModificationException; +import java.util.Objects; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.InvalidObjectException; + +/** + * Runtime exception thrown if an I/O error is encountered when iterating over + * the entries in a directory. The I/O error is retrieved as an {@link + * IOException} using the {@link #getCause() getCause()} method. + * + * @since 1.7 + * @see DirectoryStream + */ + +public final class DirectoryIteratorException + extends ConcurrentModificationException +{ + private static final long serialVersionUID = -6012699886086212874L; + + /** + * Constructs an instance of this class. + * + * @param cause + * the {@code IOException} that caused the directory iteration + * to fail + * + * @throws NullPointerException + * if the cause is {@code null} + */ + public DirectoryIteratorException(IOException cause) { + super(Objects.nonNull(cause)); + } + + /** + * Returns the cause of this exception. + * + * @return the cause + */ + @Override + public IOException getCause() { + return (IOException)super.getCause(); + } + + /** + * Called to read the object from a stream. + * + * @throws InvalidObjectException + * if the object is invalid or has a cause that is not + * an {@code IOException} + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + Throwable cause = super.getCause(); + if (!(cause instanceof IOException)) + throw new InvalidObjectException("Cause must be an IOException"); + } +} diff --git a/jdk/src/share/classes/java/nio/file/DirectoryStream.java b/jdk/src/share/classes/java/nio/file/DirectoryStream.java index 61fa52cec4d..fd7bf85c939 100644 --- a/jdk/src/share/classes/java/nio/file/DirectoryStream.java +++ b/jdk/src/share/classes/java/nio/file/DirectoryStream.java @@ -31,60 +31,84 @@ import java.io.IOException; /** * An object to iterate over the entries in a directory. A directory stream - * allows for convenient use of the for-each construct: + * allows for the convenient use of the for-each construct to iterate over a + * directory. + * + *

While {@code DirectoryStream} extends {@code Iterable}, it is not a + * general-purpose {@code Iterable} as it supports only a single {@code + * Iterator}; invoking the {@link #iterator iterator} method to obtain a second + * or subsequent iterator throws {@code IllegalStateException}. + * + *

An important property of the directory stream's {@code Iterator} is that + * its {@link Iterator#hasNext() hasNext} method is guaranteed to read-ahead by + * at least one element. If {@code hasNext} method returns {@code true}, and is + * followed by a call to the {@code next} method, it is guaranteed that the + * {@code next} method will not throw an exception due to an I/O error, or + * because the stream has been {@link #close closed}. The {@code Iterator} does + * not support the {@link Iterator#remove remove} operation. + * + *

A {@code DirectoryStream} is opened upon creation and is closed by + * invoking the {@code close} method. Closing a directory stream releases any + * resources associated with the stream. Failure to close the stream may result + * in a resource leak. The try-with-resources statement provides a useful + * construct to ensure that the stream is closed: *

  *   Path dir = ...
- *   DirectoryStream<Path> stream = dir.newDirectoryStream();
- *   try {
+ *   try (DirectoryStream<Path> stream = dir.newDirectoryStream()) {
  *       for (Path entry: stream) {
- *         ..
+ *           ...
  *       }
- *   } finally {
- *       stream.close();
  *   }
  * 
* - *

A {@code DirectoryStream} is not a general-purpose {@code Iterable}. - * While this interface extends {@code Iterable}, the {@code iterator} method - * may only be invoked once to obtain the iterator; a second, or subsequent, - * call to the {@code iterator} method throws {@code IllegalStateException}. - * - *

A {@code DirectoryStream} is opened upon creation and is closed by - * invoking the {@link #close close} method. Closing the directory stream - * releases any resources associated with the stream. Once a directory stream - * is closed, all further method invocations on the iterator throw {@link - * java.util.ConcurrentModificationException} with cause {@link - * ClosedDirectoryStreamException}. + *

Once a directory stream is closed, then further access to the directory, + * using the {@code Iterator}, behaves as if the end of stream has been reached. + * Due to read-ahead, the {@code Iterator} may return one or more elements + * after the directory stream has been closed. Once these buffered elements + * have been read, then subsequent calls to the {@code hasNext} method returns + * {@code false}, and subsequent calls to the {@code next} method will throw + * {@code NoSuchElementException}. * *

A directory stream is not required to be asynchronously closeable. * If a thread is blocked on the directory stream's iterator reading from the * directory, and another thread invokes the {@code close} method, then the * second thread may block until the read operation is complete. * - *

The {@link Iterator#hasNext() hasNext} and {@link Iterator#next() next} - * methods can encounter an I/O error when iterating over the directory in which - * case {@code ConcurrentModificationException} is thrown with cause - * {@link java.io.IOException}. The {@code hasNext} method is guaranteed to - * read-ahead by at least one element. This means that if the {@code hasNext} - * method returns {@code true} and is followed by a call to the {@code next} - * method then it is guaranteed not to fail with a {@code - * ConcurrentModificationException}. + *

If an I/O error is encountered when accessing the directory then it + * causes the {@code Iterator}'s {@code hasNext} or {@code next} methods to + * throw {@link DirectoryIteratorException} with the {@link IOException} as the + * cause. As stated above, the {@code hasNext} method is guaranteed to + * read-ahead by at least one element. This means that if {@code hasNext} method + * returns {@code true}, and is followed by a call to the {@code next} method, + * then it is guaranteed that the {@code next} method will not fail with a + * {@code DirectoryIteratorException}. * *

The elements returned by the iterator are in no specific order. Some file * systems maintain special links to the directory itself and the directory's * parent directory. Entries representing these links are not returned by the * iterator. * - *

The iterator's {@link Iterator#remove() remove} method removes the - * directory entry for the last element returned by the iterator, as if by - * invoking the {@link Path#delete delete} method. If an I/O error or - * security exception occurs then {@code ConcurrentModificationException} is - * thrown with the cause. - * *

The iterator is weakly consistent. It is thread safe but does not * freeze the directory while iterating, so it may (or may not) reflect updates * to the directory that occur after the {@code DirectoryStream} is created. * + *

Usage Examples: + * Suppose we want a list of the source files in a directory. This example uses + * both the for-each and try-with-resources constructs. + *

+ *   List<Path> listSourceFiles(Path dir) throws IOException {
+ *       List<Path> result = new ArrayList<Path>();
+ *       try (DirectoryStream<Path> stream = dir.newDirectoryStream("*.{c,h,cpp,hpp,java}")) {
+ *           for (Path entry: stream) {
+ *               result.add(entry);
+ *           }
+ *       } catch (DirectoryIteratorException ex) {
+ *           // I/O error encounted during the iteration, the cause is an IOException
+ *           throw ex.getCause();
+ *       }
+ *       return result;
+ *   }
+ * 
* @param The type of element returned by the iterator * * @since 1.7 diff --git a/jdk/src/share/classes/java/nio/file/Path.java b/jdk/src/share/classes/java/nio/file/Path.java index 029feee58a0..abdc77750cc 100644 --- a/jdk/src/share/classes/java/nio/file/Path.java +++ b/jdk/src/share/classes/java/nio/file/Path.java @@ -984,11 +984,11 @@ public abstract class Path * directory. * *

Where the filter terminates due to an uncaught error or runtime - * exception then it is propogated to the iterator's {@link Iterator#hasNext() + * exception then it is propagated to the {@link Iterator#hasNext() * hasNext} or {@link Iterator#next() next} method. Where an {@code - * IOException} is thrown, it is propogated as a {@link - * java.util.ConcurrentModificationException} with the {@code - * IOException} as the cause. + * IOException} is thrown, it results in the {@code hasNext} or {@code + * next} method throwing a {@link DirectoryIteratorException} with the + * {@code IOException} as the cause. * *

When an implementation supports operations on entries in the * directory that execute in a race-free manner then the returned directory diff --git a/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java b/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java index 362d1f547ea..d4b00e1158c 100644 --- a/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java +++ b/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java @@ -47,15 +47,6 @@ import java.io.IOException; * newDirectoryStream} method will be a {@code SecureDirectoryStream} and must * be cast to that type in order to invoke the methods defined by this interface. * - *

As specified by {@code DirectoryStream}, the iterator's {@link - * java.util.Iterator#remove() remove} method removes the directory entry for - * the last element returned by the iterator. In the case of a {@code - * SecureDirectoryStream} the {@code remove} method behaves as if by invoking - * the {@link #deleteFile deleteFile} or {@link #deleteDirectory deleteDirectory} - * methods defined by this interface. The {@code remove} may require to examine - * the file to determine if the file is a directory, and consequently, it may - * not be atomic with respect to other file system operations. - * *

In the case of the default {@link java.nio.file.spi.FileSystemProvider * provider}, and a security manager is set, then the permission checks are * performed using the path obtained by resolving the given relative path diff --git a/jdk/src/share/classes/java/security/KeyStore.java b/jdk/src/share/classes/java/security/KeyStore.java index 7ecac8025c1..c1e2e4649e7 100644 --- a/jdk/src/share/classes/java/security/KeyStore.java +++ b/jdk/src/share/classes/java/security/KeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,17 +131,19 @@ import javax.security.auth.callback.*; * to read existing entries from the keystore, or to write new entries * into the keystore: *

+ *    KeyStore.ProtectionParameter protParam =
+ *        new KeyStore.PasswordProtection(password);
+ *
  *    // get my private key
  *    KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
- *        ks.getEntry("privateKeyAlias", password);
+ *        ks.getEntry("privateKeyAlias", protParam);
  *    PrivateKey myPrivateKey = pkEntry.getPrivateKey();
  *
  *    // save my secret key
  *    javax.crypto.SecretKey mySecretKey;
  *    KeyStore.SecretKeyEntry skEntry =
  *        new KeyStore.SecretKeyEntry(mySecretKey);
- *    ks.setEntry("secretKeyAlias", skEntry,
- *        new KeyStore.PasswordProtection(password));
+ *    ks.setEntry("secretKeyAlias", skEntry, protParam);
  *
  *    // store away the keystore
  *    java.io.FileOutputStream fos = null;
diff --git a/jdk/src/share/classes/java/sql/CallableStatement.java b/jdk/src/share/classes/java/sql/CallableStatement.java
index c328858de36..2f2a77594e1 100644
--- a/jdk/src/share/classes/java/sql/CallableStatement.java
+++ b/jdk/src/share/classes/java/sql/CallableStatement.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -2436,4 +2436,64 @@ public interface CallableStatement extends PreparedStatement {
      */
      void setNClob(String parameterName, Reader reader)
        throws SQLException;
+
+    //------------------------- JDBC 4.1 -----------------------------------
+
+
+    /**
+     *

Returns an object representing the value of OUT parameter + * {@code parameterIndex} and will convert from the + * SQL type of the parameter to the requested Java data type, if the + * conversion is supported. If the conversion is not + * supported or null is specified for the type, a + * SQLException is thrown. + *

+ * At a minimum, an implementation must support the conversions defined in + * Appendix B, Table B-3 and conversion of appropriate user defined SQL + * types to a Java type which implements {@code SQLData}, or {@code Struct}. + * Additional conversions may be supported and are vendor defined. + * + * @param parameterIndex the first parameter is 1, the second is 2, and so on + * @param type Class representing the Java data type to convert the + * designated parameter to. + * @return an instance of {@code type} holding the OUT parameter value + * @throws SQLException if conversion is not supported, type is null or + * another error occurs. The getCause() method of the + * exception may provide a more detailed exception, for example, if + * a conversion error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not support + * this method + * @since 1.7 + */ + public T getObject(int parameterIndex, Class type) throws SQLException; + + + /** + *

Returns an object representing the value of OUT parameter + * {@code parameterName} and will convert from the + * SQL type of the parameter to the requested Java data type, if the + * conversion is supported. If the conversion is not + * supported or null is specified for the type, a + * SQLException is thrown. + *

+ * At a minimum, an implementation must support the conversions defined in + * Appendix B, Table B-3 and conversion of appropriate user defined SQL + * types to a Java type which implements {@code SQLData}, or {@code Struct}. + * Additional conversions may be supported and are vendor defined. + * + * @param parameterName the name of the parameter + * @param type Class representing the Java data type to convert + * the designated parameter to. + * @return an instance of {@code type} holding the OUT parameter + * value + * @throws SQLException if conversion is not supported, type is null or + * another error occurs. The getCause() method of the + * exception may provide a more detailed exception, for example, if + * a conversion error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not support + * this method + * @since 1.7 + */ + public T getObject(String parameterName, Class type) throws SQLException; + } diff --git a/jdk/src/share/classes/java/sql/Connection.java b/jdk/src/share/classes/java/sql/Connection.java index b850e25a38d..9b6706562ba 100644 --- a/jdk/src/share/classes/java/sql/Connection.java +++ b/jdk/src/share/classes/java/sql/Connection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package java.sql; import java.util.Properties; +import java.util.concurrent.Executor; /** *

A connection (session) with a specific @@ -38,7 +39,7 @@ import java.util.Properties; * information is obtained with the getMetaData method. * *

Note: When configuring a Connection, JDBC applications - * should use the appropritate Connection method such as + * should use the appropriate Connection method such as * setAutoCommit or setTransactionIsolation. * Applications should not invoke SQL commands directly to change the connection's * configuration when there is a JDBC method available. By default a Connection object is in @@ -80,7 +81,7 @@ import java.util.Properties; * @see ResultSet * @see DatabaseMetaData */ -public interface Connection extends Wrapper { +public interface Connection extends Wrapper, AutoCloseable { /** * Creates a Statement object for sending @@ -347,6 +348,13 @@ public interface Connection extends Wrapper { *

* If the driver does not support catalogs, it will * silently ignore this request. + *

+ * Calling {@code setCatalog} has no effect on previously created or prepared + * {@code Statement} objects. It is implementation defined whether a DBMS + * prepare operation takes place immediately when the {@code Connection} + * method {@code prepareStatement} or {@code prepareCall} is invoked. + * For maximum portability, {@code setCatalog} should be called before a + * {@code Statement} is created or prepared. * * @param catalog the name of a catalog (subspace in this * Connection object's database) in which to work @@ -598,7 +606,17 @@ public interface Connection extends Wrapper { * Connection object. * Unless the application has added an entry, the type map returned * will be empty. - * + *

+ * You must invoke setTypeMap after making changes to the + * Map object returned from + * getTypeMap as a JDBC driver may create an internal + * copy of the Map object passed to setTypeMap: + *

+ *

+     *      Map<String,Class<?>> myMap = con.getTypeMap();
+     *      myMap.put("mySchemaName.ATHLETES", Athletes.class);
+     *      con.setTypeMap(myMap);
+     * 
* @return the java.util.Map object associated * with this Connection object * @exception SQLException if a database access error occurs @@ -614,7 +632,16 @@ public interface Connection extends Wrapper { * Installs the given TypeMap object as the type map for * this Connection object. The type map will be used for the * custom mapping of SQL structured types and distinct types. - * + *

+ * You must set the the values for the TypeMap prior to + * callng setMap as a JDBC driver may create an internal copy + * of the TypeMap: + *

+ *

+     *      Map myMap<String,Class<?>> = new HashMap<String,Class<?>>();
+     *      myMap.put("mySchemaName.ATHLETES", Athletes.class);
+     *      con.setTypeMap(myMap);
+     * 
* @param map the java.util.Map object to install * as the replacement for this Connection * object's default type map @@ -1274,4 +1301,186 @@ SQLException; */ Struct createStruct(String typeName, Object[] attributes) throws SQLException; + + //--------------------------JDBC 4.1 ----------------------------- + + /** + * Sets the given schema name to access. + *

+ * If the driver does not support schemas, it will + * silently ignore this request. + *

+ * Calling {@code setSchema} has no effect on previously created or prepared + * {@code Statement} objects. It is implementation defined whether a DBMS + * prepare operation takes place immediately when the {@code Connection} + * method {@code prepareStatement} or {@code prepareCall} is invoked. + * For maximum portability, {@code setSchema} should be called before a + * {@code Statement} is created or prepared. + * + * @param schema the name of a schema in which to work + * @exception SQLException if a database access error occurs + * or this method is called on a closed connection + * @see #getSchema + * @since 1.7 + */ + void setSchema(String schema) throws SQLException; + + /** + * Retrieves this Connection object's current schema name. + * + * @return the current schema name or null if there is none + * @exception SQLException if a database access error occurs + * or this method is called on a closed connection + * @see #setSchema + * @since 1.7 + */ + String getSchema() throws SQLException; + + /** + * Terminates an open connection. Calling abort results in: + *

    + *
  • The connection marked as closed + *
  • Closes any physical connection to the database + *
  • Releases resources used by the connection + *
  • Insures that any thread that is currently accessing the connection + * will either progress to completion or throw an SQLException. + *
+ *

+ * Calling abort marks the connection closed and releases any + * resources. Calling abort on a closed connection is a + * no-op. + *

+ * It is possible that the aborting and releasing of the resources that are + * held by the connection can take an extended period of time. When the + * abort method returns, the connection will have been marked as + * closed and the Executor that was passed as a parameter to abort + * may still be executing tasks to release resources. + *

+ * This method checks to see that there is an SQLPermission + * object before allowing the method to proceed. If a + * SecurityManager exists and its + * checkPermission method denies calling abort, + * this method throws a + * java.lang.SecurityException. + * @param executor The Executor implementation which will + * be used by abort. + * @throws java.sql.SQLException if a database access error occurs or + * the {@code executor} is {@code null}, + * @throws java.lang.SecurityException if a security manager exists and its + * checkPermission method denies calling abort + * @see SecurityManager#checkPermission + * @see Executor + * @since 1.7 + */ + void abort(Executor executor) throws SQLException; + + /** + * + * Sets the maximum period a Connection or + * objects created from the Connection + * will wait for the database to reply to any one request. If any + * request remains unanswered, the waiting method will + * return with a SQLException, and the Connection + * or objects created from the Connection will be marked as + * closed. Any subsequent use of + * the objects, with the exception of the close, + * isClosed or Connection.isValid + * methods, will result in a SQLException. + *

+ * Note: This method is intended to address a rare but serious + * condition where network partitions can cause threads issuing JDBC calls + * to hang uninterruptedly in socket reads, until the OS TCP-TIMEOUT + * (typically 10 minutes). This method is related to the + * {@link #abort abort() } method which provides an administrator + * thread a means to free any such threads in cases where the + * JDBC connection is accessible to the administrator thread. + * The setNetworkTimeout method will cover cases where + * there is no administrator thread, or it has no access to the + * connection. This method is severe in it's effects, and should be + * given a high enough value so it is never triggered before any more + * normal timeouts, such as transaction timeouts. + *

+ * JDBC driver implementations may also choose to support the + * {@code setNetworkTimeout} method to impose a limit on database + * response time, in environments where no network is present. + *

+ * Drivers may internally implement some or all of their API calls with + * multiple internal driver-database transmissions, and it is left to the + * driver implementation to determine whether the limit will be + * applied always to the response to the API call, or to any + * single request made during the API call. + *

+ * + * This method can be invoked more than once, such as to set a limit for an + * area of JDBC code, and to reset to the default on exit from this area. + * Invocation of this method has no impact on already outstanding + * requests. + *

+ * The {@code Statement.setQueryTimeout()} timeout value is independent of the + * timeout value specified in {@code setNetworkTimeout}. If the query timeout + * expires before the network timeout then the + * statement execution will be canceled. If the network is still + * active the result will be that both the statement and connection + * are still usable. However if the network timeout expires before + * the query timeout or if the statement timeout fails due to network + * problems, the connection will be marked as closed, any resources held by + * the connection will be released and both the connection and + * statement will be unusable. + *

+ * When the driver determines that the {@code setNetworkTimeout} timeout + * value has expired, the JDBC driver marks the connection + * closed and releases any resources held by the connection. + *

+ * + * This method checks to see that there is an SQLPermission + * object before allowing the method to proceed. If a + * SecurityManager exists and its + * checkPermission method denies calling + * setNetworkTimeout, this method throws a + * java.lang.SecurityException. + * + * @param executor The Executor implementation which will + * be used by setNetworkTimeout. + * @param milliseconds The time in milliseconds to wait for the database + * operation + * to complete. If the JDBC driver does not support milliseconds, the + * JDBC driver will round the value up to the nearest second. If the + * timeout period expires before the operation + * completes, a SQLException will be thrown. + * A value of 0 indicates that there is not timeout for database operations. + * @throws java.sql.SQLException if a database access error occurs, this + * method is called on a closed connection, + * the {@code executor} is {@code null}, + * or the value specified for seconds is less than 0. + * @throws java.lang.SecurityException if a security manager exists and its + * checkPermission method denies calling + * setNetworkTimeout. + * @exception SQLFeatureNotSupportedException if the JDBC driver does not support + * this method + * @see SecurityManager#checkPermission + * @see Statement#setQueryTimeout + * @see #getNetworkTimeout + * @see #abort + * @see Executor + * @since 1.7 + */ + void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException; + + + /** + * Retrieves the number of milliseconds the driver will + * wait for a database request to complete. + * If the limit is exceeded, a + * SQLException is thrown. + * + * @return the current timeout limit in milliseconds; zero means there is + * no limit + * @throws SQLException if a database access error occurs or + * this method is called on a closed Connection + * @exception SQLFeatureNotSupportedException if the JDBC driver does not support + * this method + * @see #setNetworkTimeout + * @since 1.7 + */ + int getNetworkTimeout() throws SQLException; } diff --git a/jdk/src/share/classes/java/sql/DatabaseMetaData.java b/jdk/src/share/classes/java/sql/DatabaseMetaData.java index 07923026203..d867986c6bf 100644 --- a/jdk/src/share/classes/java/sql/DatabaseMetaData.java +++ b/jdk/src/share/classes/java/sql/DatabaseMetaData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1342,10 +1342,10 @@ public interface DatabaseMetaData extends Wrapper { * defined. *

  • IS_NULLABLE String => ISO rules are used to determine the nullability for a column. *
      - *
    • YES --- if the parameter can include NULLs - *
    • NO --- if the parameter cannot include NULLs + *
    • YES --- if the column can include NULLs + *
    • NO --- if the column cannot include NULLs *
    • empty string --- if the nullability for the - * parameter is unknown + * column is unknown *
    *
  • SPECIFIC_NAME String => the name which uniquely identifies this procedure within its schema. * @@ -1610,17 +1610,17 @@ public interface DatabaseMetaData extends Wrapper { * (starting at 1) *
  • IS_NULLABLE String => ISO rules are used to determine the nullability for a column. *
      - *
    • YES --- if the parameter can include NULLs - *
    • NO --- if the parameter cannot include NULLs + *
    • YES --- if the column can include NULLs + *
    • NO --- if the column cannot include NULLs *
    • empty string --- if the nullability for the - * parameter is unknown + * column is unknown *
    - *
  • SCOPE_CATLOG String => catalog of table that is the scope + *
  • SCOPE_CATALOG String => catalog of table that is the scope * of a reference attribute (null if DATA_TYPE isn't REF) *
  • SCOPE_SCHEMA String => schema of table that is the scope * of a reference attribute (null if the DATA_TYPE isn't REF) *
  • SCOPE_TABLE String => table name that this the scope - * of a reference attribure (null if the DATA_TYPE isn't REF) + * of a reference attribute (null if the DATA_TYPE isn't REF) *
  • SOURCE_DATA_TYPE short => source type of a distinct type or user-generated * Ref type, SQL type from java.sql.Types (null if DATA_TYPE * isn't DISTINCT or user-generated REF) @@ -1629,11 +1629,16 @@ public interface DatabaseMetaData extends Wrapper { *
  • YES --- if the column is auto incremented *
  • NO --- if the column is not auto incremented *
  • empty string --- if it cannot be determined whether the column is auto incremented - * parameter is unknown + * + *
  • IS_GENERATEDCOLUMN String => Indicates whether this is a generated column + *
      + *
    • YES --- if this a generated column + *
    • NO --- if this not a generated column + *
    • empty string --- if it cannot be determined whether this is a generated column *
    * * - *

    The COLUMN_SIZE column the specified column size for the given column. + *

    The COLUMN_SIZE column specifies the column size for the given column. * For numeric data, this is the maximum precision. For character data, this is the length in characters. * For datetime datatypes, this is the length in characters of the String representation (assuming the * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes. For the ROWID datatype, @@ -3186,7 +3191,7 @@ public interface DatabaseMetaData extends Wrapper { * Retrieves whether this database supports statement pooling. * * @return true if so; false otherwise - * @throws SQLExcpetion if a database access error occurs + * @throws SQLException if a database access error occurs * @since 1.4 */ boolean supportsStatementPooling() throws SQLException; @@ -3568,4 +3573,83 @@ public interface DatabaseMetaData extends Wrapper { */ int functionReturnsTable = 2; + //--------------------------JDBC 4.1 ----------------------------- + + /** + * Retrieves a description of the pseudo or hidden columns available + * in a given table within the specified catalog and schema. + * Pseudo or hidden columns may not always be stored within + * a table and are not visible in a ResultSet unless they are + * specified in the query's outermost SELECT list. Pseudo or hidden + * columns may not necessarily be able to be modified. If there are + * no pseudo or hidden columns, an empty ResultSet is returned. + * + *

    Only column descriptions matching the catalog, schema, table + * and column name criteria are returned. They are ordered by + * TABLE_CAT,TABLE_SCHEM, TABLE_NAME + * and COLUMN_NAME. + * + *

    Each column description has the following columns: + *

      + *
    1. TABLE_CAT String => table catalog (may be null) + *
    2. TABLE_SCHEM String => table schema (may be null) + *
    3. TABLE_NAME String => table name + *
    4. COLUMN_NAME String => column name + *
    5. DATA_TYPE int => SQL type from java.sql.Types + *
    6. COLUMN_SIZE int => column size. + *
    7. DECIMAL_DIGITS int => the number of fractional digits. Null is returned for data types where + * DECIMAL_DIGITS is not applicable. + *
    8. NUM_PREC_RADIX int => Radix (typically either 10 or 2) + *
    9. COLUMN_USAGE String => The allowed usage for the column. The + * value returned will correspond to the enum name returned by {@link PseudoColumnUsage#name PseudoColumnUsage.name()} + *
    10. REMARKS String => comment describing column (may be null) + *
    11. CHAR_OCTET_LENGTH int => for char types the + * maximum number of bytes in the column + *
    12. IS_NULLABLE String => ISO rules are used to determine the nullability for a column. + *
        + *
      • YES --- if the column can include NULLs + *
      • NO --- if the column cannot include NULLs + *
      • empty string --- if the nullability for the column is unknown + *
      + *
    + * + *

    The COLUMN_SIZE column specifies the column size for the given column. + * For numeric data, this is the maximum precision. For character data, this is the length in characters. + * For datetime datatypes, this is the length in characters of the String representation (assuming the + * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes. For the ROWID datatype, + * this is the length in bytes. Null is returned for data types where the + * column size is not applicable. + * + * @param catalog a catalog name; must match the catalog name as it + * is stored in the database; "" retrieves those without a catalog; + * null means that the catalog name should not be used to narrow + * the search + * @param schemaPattern a schema name pattern; must match the schema name + * as it is stored in the database; "" retrieves those without a schema; + * null means that the schema name should not be used to narrow + * the search + * @param tableNamePattern a table name pattern; must match the + * table name as it is stored in the database + * @param columnNamePattern a column name pattern; must match the column + * name as it is stored in the database + * @return ResultSet - each row is a column description + * @exception SQLException if a database access error occurs + * @see PseudoColumnUsage + * @since 1.7 + */ + ResultSet getPseudoColumns(String catalog, String schemaPattern, + String tableNamePattern, String columnNamePattern) + throws SQLException; + + /** + * Retrieves whether a generated key will always be returned if the column + * name(s) or indexe(s) specified for the auto generated key column(s) + * are valid and the statement succeeds. The key that is returned may or + * may not be based on the column(s) for the auto generated key. + * Consult your JDBC driver documentation for additional details. + * @return true if so; false otherwise + * @exception SQLException if a database access error occurs + * @since 1.7 + */ + boolean generatedKeyAlwaysReturned() throws SQLException; } diff --git a/jdk/src/share/classes/java/sql/Date.java b/jdk/src/share/classes/java/sql/Date.java index 39cf98ce93f..1d82ab36a1b 100644 --- a/jdk/src/share/classes/java/sql/Date.java +++ b/jdk/src/share/classes/java/sql/Date.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,34 +96,55 @@ public class Date extends java.util.Date { * a Date value. * * @param s a String object representing a date in - * in the format "yyyy-mm-dd" + * in the format "yyyy-[m]m-[d]d". The leading zero for mm + * and dd may also be omitted. * @return a java.sql.Date object representing the * given date * @throws IllegalArgumentException if the date given is not in the - * JDBC date escape format (yyyy-mm-dd) + * JDBC date escape format (yyyy-[m]m-[d]d) */ public static Date valueOf(String s) { - int year; - int month; - int day; + final int YEAR_LENGTH = 4; + final int MONTH_LENGTH = 2; + final int DAY_LENGTH = 2; + final int MAX_MONTH = 12; + final int MAX_DAY = 31; int firstDash; int secondDash; + Date d = null; - if (s == null) throw new java.lang.IllegalArgumentException(); - - firstDash = s.indexOf('-'); - secondDash = s.indexOf('-', firstDash+1); - if ((firstDash > 0) & (secondDash > 0) & (secondDash < s.length()-1)) { - year = Integer.parseInt(s.substring(0, firstDash)) - 1900; - month = Integer.parseInt(s.substring(firstDash+1, secondDash)) - 1; - day = Integer.parseInt(s.substring(secondDash+1)); - } else { + if (s == null) { throw new java.lang.IllegalArgumentException(); } - return new Date(year, month, day); + firstDash = s.indexOf('-'); + secondDash = s.indexOf('-', firstDash + 1); + + if ((firstDash > 0) && (secondDash > 0) && (secondDash < s.length() - 1)) { + String yyyy = s.substring(0, firstDash); + String mm = s.substring(firstDash + 1, secondDash); + String dd = s.substring(secondDash + 1); + if (yyyy.length() == YEAR_LENGTH && + (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) && + (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) { + int year = Integer.parseInt(yyyy); + int month = Integer.parseInt(mm); + int day = Integer.parseInt(dd); + + if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) { + d = new Date(year - 1900, month - 1, day); + } + } + } + if (d == null) { + throw new java.lang.IllegalArgumentException(); + } + + return d; + } + /** * Formats a date in the date escape format yyyy-mm-dd. *

    diff --git a/jdk/src/share/classes/java/sql/Driver.java b/jdk/src/share/classes/java/sql/Driver.java index 8325452534c..4abc6b3c81f 100644 --- a/jdk/src/share/classes/java/sql/Driver.java +++ b/jdk/src/share/classes/java/sql/Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package java.sql; +import java.util.logging.Logger; + /** * The interface that every driver class must implement. *

    The Java SQL framework allows for multiple database drivers. @@ -150,4 +152,19 @@ public interface Driver { * otherwise */ boolean jdbcCompliant(); + + //------------------------- JDBC 4.1 ----------------------------------- + + /** + * Return the parent Logger of all the Loggers used by this driver. This + * should be the Logger farthest from the root Logger that is + * still an ancestor of all of the Loggers used by this driver. Configuring + * this Logger will affect all of the log messages generated by the driver. + * In the worst case, this may be the root Logger. + * + * @return the parent Logger for this driver + * @throws SQLFeatureNotSupportedException if the driver does not use java.util.logging. + * @since 1.7 + */ + public Logger getParentLogger() throws SQLFeatureNotSupportedException; } diff --git a/jdk/src/share/classes/java/sql/PreparedStatement.java b/jdk/src/share/classes/java/sql/PreparedStatement.java index eb55d199fcc..1d32c3dd0b9 100644 --- a/jdk/src/share/classes/java/sql/PreparedStatement.java +++ b/jdk/src/share/classes/java/sql/PreparedStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,6 +69,10 @@ public interface PreparedStatement extends Statement { * @exception SQLException if a database access error occurs; * this method is called on a closed PreparedStatement or the SQL * statement does not return a ResultSet object + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} */ ResultSet executeQuery() throws SQLException; @@ -82,8 +86,11 @@ public interface PreparedStatement extends Statement { * or (2) 0 for SQL statements that return nothing * @exception SQLException if a database access error occurs; * this method is called on a closed PreparedStatement - * or the SQL - * statement returns a ResultSet object + * or the SQL statement returns a ResultSet object + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} */ int executeUpdate() throws SQLException; @@ -463,6 +470,10 @@ public interface PreparedStatement extends Statement { * @exception SQLException if a database access error occurs; * this method is called on a closed PreparedStatement * or an argument is supplied to this method + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} * @see Statement#execute * @see Statement#getResultSet * @see Statement#getUpdateCount @@ -1208,4 +1219,5 @@ public interface PreparedStatement extends Statement { void setNClob(int parameterIndex, Reader reader) throws SQLException; + } diff --git a/jdk/src/share/classes/java/sql/PseudoColumnUsage.java b/jdk/src/share/classes/java/sql/PseudoColumnUsage.java new file mode 100644 index 00000000000..bc9c1add47c --- /dev/null +++ b/jdk/src/share/classes/java/sql/PseudoColumnUsage.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.sql; + + +/** + * Enumeration for pseudo/hidden column usage. + * + * @since 1.7 + * @see DatabaseMetaData#getPseudoColumns + */ +public enum PseudoColumnUsage { + + /** + * The pseudo/hidden column may only be used in a SELECT list. + */ + SELECT_LIST_ONLY, + + /** + * The pseudo/hidden column may only be used in a WHERE clause. + */ + WHERE_CLAUSE_ONLY, + + /** + * There are no restrictions on the usage of the pseudo/hidden columns. + */ + NO_USAGE_RESTRICTIONS, + + /** + * The usage of the pseudo/hidden column cannot be determined. + */ + USAGE_UNKNOWN + +} diff --git a/jdk/src/share/classes/java/sql/ResultSet.java b/jdk/src/share/classes/java/sql/ResultSet.java index 579270c783f..a8aac4ffeea 100644 --- a/jdk/src/share/classes/java/sql/ResultSet.java +++ b/jdk/src/share/classes/java/sql/ResultSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -145,7 +145,7 @@ import java.io.InputStream; * @see ResultSetMetaData */ -public interface ResultSet extends Wrapper { +public interface ResultSet extends Wrapper, AutoCloseable { /** * Moves the cursor froward one row from its current position. @@ -1187,6 +1187,9 @@ public interface ResultSet extends Wrapper { * cursor on the last row; calling the method absolute(-2) * moves the cursor to the next-to-last row, and so on. * + *

    If the row number specified is zero, the cursor is moved to + * before the first row. + * *

    An attempt to position the cursor beyond the first/last row in * the result set leaves the cursor before the first row or after * the last row. @@ -1196,9 +1199,10 @@ public interface ResultSet extends Wrapper { * is the same as calling last(). * * @param row the number of the row to which the cursor should move. - * A positive number indicates the row number counting from the - * beginning of the result set; a negative number indicates the - * row number counting from the end of the result set + * A value of zero indicates that the cursor will be positioned + * before the first row; a positive number indicates the row number + * counting from the beginning of the result set; a negative number + * indicates the row number counting from the end of the result set * @return true if the cursor is moved to a position in this * ResultSet object; * false if the cursor is before the first row or after the @@ -2529,7 +2533,7 @@ public interface ResultSet extends Wrapper { * @exception SQLException if the columnLabel is not valid; * if a database access error occurs * or this method is called on a closed result set - * @exception SQLFeatureNotSupportedException if the JDBC driver does not support + * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since 1.2 */ @@ -4072,4 +4076,64 @@ public interface ResultSet extends Wrapper { */ void updateNClob(String columnLabel, Reader reader) throws SQLException; + //------------------------- JDBC 4.1 ----------------------------------- + + + /** + *

    Retrieves the value of the designated column in the current row + * of this ResultSet object and will convert from the + * SQL type of the column to the requested Java data type, if the + * conversion is supported. If the conversion is not + * supported or null is specified for the type, a + * SQLException is thrown. + *

    + * At a minimum, an implementation must support the conversions defined in + * Appendix B, Table B-3 and conversion of appropriate user defined SQL + * types to a Java type which implements {@code SQLData}, or {@code Struct}. + * Additional conversions may be supported and are vendor defined. + * + * @param columnIndex the first column is 1, the second is 2, ... + * @param type Class representing the Java data type to convert the designated + * column to. + * @return an instance of {@code type} holding the column value + * @throws SQLException if conversion is not supported, type is null or + * another error occurs. The getCause() method of the + * exception may provide a more detailed exception, for example, if + * a conversion error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not support + * this method + * @since 1.7 + */ + public T getObject(int columnIndex, Class type) throws SQLException; + + + /** + *

    Retrieves the value of the designated column in the current row + * of this ResultSet object and will convert from the + * SQL type of the column to the requested Java data type, if the + * conversion is supported. If the conversion is not + * supported or null is specified for the type, a + * SQLException is thrown. + *

    + * At a minimum, an implementation must support the conversions defined in + * Appendix B, Table B-3 and conversion of appropriate user defined SQL + * types to a Java type which implements {@code SQLData}, or {@code Struct}. + * Additional conversions may be supported and are vendor defined. + * + * @param columnLabel the label for the column specified with the SQL AS clause. + * If the SQL AS clause was not specified, then the label is the name + * of the column + * @param type Class representing the Java data type to convert the designated + * column to. + * @return an instance of {@code type} holding the column value + * @throws SQLException if conversion is not supported, type is null or + * another error occurs. The getCause() method of the + * exception may provide a more detailed exception, for example, if + * a conversion error occurs + * @throws SQLFeatureNotSupportedException if the JDBC driver does not support + * this method + * @since 1.7 + */ + public T getObject(String columnLabel, Class type) throws SQLException; + } diff --git a/jdk/src/share/classes/java/sql/SQLDataException.java b/jdk/src/share/classes/java/sql/SQLDataException.java index 813b9949782..8dc1753a6b7 100644 --- a/jdk/src/share/classes/java/sql/SQLDataException.java +++ b/jdk/src/share/classes/java/sql/SQLDataException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,13 @@ package java.sql; /** - * The subclass of {@link SQLException} thrown when the SQLState class value is '22'. This indicates - * various data errors, including but not limited to not-allowed conversion, division by 0 - * and invalid arguments to functions. - * + * The subclass of {@link SQLException} thrown when the SQLState class value + * is '22', or under vendor-specified conditions. This indicates + * various data errors, including but not limited to data conversion errors, + * division by 0, and invalid arguments to functions. + *

    + * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLDataException extends SQLNonTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLIntegrityConstraintViolationException.java b/jdk/src/share/classes/java/sql/SQLIntegrityConstraintViolationException.java index 0c7160d2675..0f92ac50dfa 100644 --- a/jdk/src/share/classes/java/sql/SQLIntegrityConstraintViolationException.java +++ b/jdk/src/share/classes/java/sql/SQLIntegrityConstraintViolationException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,13 @@ package java.sql; /** - * The subclass of {@link SQLException} thrown when the SQLState class value is '23'. This indicates that an integrity + * The subclass of {@link SQLException} thrown when the SQLState class value + * is '23', or under vendor-specified conditions. + * This indicates that an integrity * constraint (foreign key, primary key or unique key) has been violated. - * + *

    + * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLIntegrityConstraintViolationException extends SQLNonTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLInvalidAuthorizationSpecException.java b/jdk/src/share/classes/java/sql/SQLInvalidAuthorizationSpecException.java index 34ccfe13301..0b4d206df96 100644 --- a/jdk/src/share/classes/java/sql/SQLInvalidAuthorizationSpecException.java +++ b/jdk/src/share/classes/java/sql/SQLInvalidAuthorizationSpecException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,13 @@ package java.sql; /** - * The subclass of {@link SQLException} thrown when the SQLState class value is '28'. This indicated that the - * authorization credentials presented during connection establishment are not valid. - * + * The subclass of {@link SQLException} thrown when the SQLState class value + * is '28', or under vendor-specified conditions. This indicates that + * the authorization credentials presented during connection establishment + * are not valid. + *

    + * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLInvalidAuthorizationSpecException extends SQLNonTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLNonTransientConnectionException.java b/jdk/src/share/classes/java/sql/SQLNonTransientConnectionException.java index 089f7f439ed..036c881f205 100644 --- a/jdk/src/share/classes/java/sql/SQLNonTransientConnectionException.java +++ b/jdk/src/share/classes/java/sql/SQLNonTransientConnectionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,11 +26,13 @@ package java.sql; /** - *

    The subclass of {@link SQLException} thrown for the SQLState - * class value '08', representing - * that the connection operation that failed will not succeed when + * The subclass of {@link SQLException} thrown for the SQLState + * class value '08', or under vendor-specified conditions. This + * indicates that the connection operation that failed will not succeed if * the operation is retried without the cause of the failure being corrected. *

    + * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLNonTransientConnectionException extends java.sql.SQLNonTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLPermission.java b/jdk/src/share/classes/java/sql/SQLPermission.java index e5b3ff69e00..e7e799c1cac 100644 --- a/jdk/src/share/classes/java/sql/SQLPermission.java +++ b/jdk/src/share/classes/java/sql/SQLPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,9 +30,14 @@ import java.security.*; /** * The permission for which the SecurityManager will check - * when code that is running in an applet calls the - * DriverManager.setLogWriter method or the - * DriverManager.setLogStream (deprecated) method. + * when code that is running in an applet, or an application with a + * SecurityManager enabled, calls the + * DriverManager.setLogWriter method, + * DriverManager.setLogStream (deprecated) method, + * {@code SyncFactory.setJNDIContext} method, + * {@code SyncFactory.setLogger} method, + * {@code Connection.setNetworktimeout} method, + * or the Connection.abort method. * If there is no SQLPermission object, these methods * throw a java.lang.SecurityException as a runtime exception. *

    @@ -48,7 +53,6 @@ import java.security.*; * but *loadLibrary or a*b is not valid. *

    * The following table lists all the possible SQLPermission target names. - * Currently, the only name allowed is setLog. * The table gives a description of what the permission allows * and a discussion of the risks of granting code the permission. *

    @@ -67,9 +71,33 @@ import java.security.*; * The contents of the log may contain usernames and passwords, * SQL statements, and SQL data. * + * + * callAbort + * Allows the invocation of the {@code Connection} method + * {@code abort} + * Permits an application to terminate a physical connection to a + * database. + * + * + * setSyncFactory + * Allows the invocation of the {@code SyncFactory} methods + * {@code setJNDIContext} and {@code setLogger} + * Permits an application to specify the JNDI context from which the + * {@code SyncProvider} implementations can be retrieved from and the logging + * object to be used by the{@codeSyncProvider} implementation. + * * + * + * setNetworkTimeout + * Allows the invocation of the {@code Connection} method + * {@code setNetworkTimeout} + * Permits an application to specify the maximum period a + * Connection or + * objects created from the Connection + * will wait for the database to reply to any one request. + * * - * + *

    * The person running an applet decides what permissions to allow * and will run the Policy Tool to create an * SQLPermission in a policy file. A programmer does diff --git a/jdk/src/share/classes/java/sql/SQLSyntaxErrorException.java b/jdk/src/share/classes/java/sql/SQLSyntaxErrorException.java index a1865d93bbb..b65dec722c7 100644 --- a/jdk/src/share/classes/java/sql/SQLSyntaxErrorException.java +++ b/jdk/src/share/classes/java/sql/SQLSyntaxErrorException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,12 @@ package java.sql; /** - * The subclass of {@link SQLException} thrown when the SQLState class value is '42'. This indicates that the + * The subclass of {@link SQLException} thrown when the SQLState class value + * is '42', or under vendor-specified conditions. This indicates that the * in-progress query has violated SQL syntax rules. - * + *

    + * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLSyntaxErrorException extends SQLNonTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLTransactionRollbackException.java b/jdk/src/share/classes/java/sql/SQLTransactionRollbackException.java index 9e05add35ad..90eb702994b 100644 --- a/jdk/src/share/classes/java/sql/SQLTransactionRollbackException.java +++ b/jdk/src/share/classes/java/sql/SQLTransactionRollbackException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,13 @@ package java.sql; /** - * The subclass of {@link SQLException} thrown when the SQLState class value is '40'. This indicates that the - * current statement was automatically rolled back by the database becuase of deadlock or other - * transaction serialization failures. - * + * The subclass of {@link SQLException} thrown when the SQLState class value + * is '40', or under vendor-specified conditions. This indicates that the + * current statement was automatically rolled back by the database because + * of deadlock or other transaction serialization failures. + *

    + * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLTransactionRollbackException extends SQLTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLTransientConnectionException.java b/jdk/src/share/classes/java/sql/SQLTransientConnectionException.java index 865793c1559..cebc67d67d4 100644 --- a/jdk/src/share/classes/java/sql/SQLTransientConnectionException.java +++ b/jdk/src/share/classes/java/sql/SQLTransientConnectionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,12 @@ package java.sql; /** * The subclass of {@link SQLException} for the SQLState class - * value '08', representing - * that the connection operation that failed might be able to succeed when + * value '08', or under vendor-specified conditions. This indicates + * that the connection operation that failed might be able to succeed if * the operation is retried without any application-level changes. - *

    - * + *

    + * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLTransientConnectionException extends java.sql.SQLTransientException { diff --git a/jdk/src/share/classes/java/sql/Statement.java b/jdk/src/share/classes/java/sql/Statement.java index a99f2d348be..88684a79a57 100644 --- a/jdk/src/share/classes/java/sql/Statement.java +++ b/jdk/src/share/classes/java/sql/Statement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,20 +40,27 @@ package java.sql; * @see Connection#createStatement * @see ResultSet */ -public interface Statement extends Wrapper { +public interface Statement extends Wrapper, AutoCloseable { /** * Executes the given SQL statement, which returns a single * ResultSet object. - * + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. * @param sql an SQL statement to be sent to the database, typically a * static SQL SELECT statement * @return a ResultSet object that contains the data produced * by the given query; never null * @exception SQLException if a database access error occurs, - * this method is called on a closed Statement or the given + * this method is called on a closed Statement, the given * SQL statement produces anything other than a single - * ResultSet object + * ResultSet object, the method is called on a + * PreparedStatement or CallableStatement + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} */ ResultSet executeQuery(String sql) throws SQLException; @@ -61,7 +68,9 @@ public interface Statement extends Wrapper { * Executes the given SQL statement, which may be an INSERT, * UPDATE, or DELETE statement or an * SQL statement that returns nothing, such as an SQL DDL statement. - * + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. * @param sql an SQL Data Manipulation Language (DML) statement, such as INSERT, UPDATE or * DELETE; or an SQL statement that returns nothing, * such as a DDL statement. @@ -70,8 +79,13 @@ public interface Statement extends Wrapper { * or (2) 0 for SQL statements that return nothing * * @exception SQLException if a database access error occurs, - * this method is called on a closed Statement or the given - * SQL statement produces a ResultSet object + * this method is called on a closed Statement, the given + * SQL statement produces a ResultSet object, the method is called on a + * PreparedStatement or CallableStatement + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} */ int executeUpdate(String sql) throws SQLException; @@ -198,11 +212,21 @@ public interface Statement extends Wrapper { /** * Sets the number of seconds the driver will wait for a * Statement object to execute to the given number of seconds. - * If the limit is exceeded, an SQLException is thrown. A JDBC - * driver must apply this limit to the execute, - * executeQuery and executeUpdate methods. JDBC driver - * implementations may also apply this limit to ResultSet methods + *By default there is no limit on the amount of time allowed for a running + * statement to complete. If the limit is exceeded, an + * SQLTimeoutException is thrown. + * A JDBC driver must apply this limit to the execute, + * executeQuery and executeUpdate methods. + *

    + * Note: JDBC driver implementations may also apply this + * limit to {@code ResultSet} methods * (consult your driver vendor documentation for details). + *

    + * Note: In the case of {@code Statement} batching, it is + * implementation defined as to whether the time-out is applied to + * individual SQL commands added via the {@code addBatch} method or to + * the entire batch of SQL commands invoked by the {@code executeBatch} + * method (consult your driver vendor documentation for details). * * @param seconds the new query timeout limit in seconds; zero means * there is no limit @@ -300,13 +324,21 @@ public interface Statement extends Wrapper { * getResultSet or getUpdateCount * to retrieve the result, and getMoreResults to * move to any subsequent result(s). - * + *

    + *Note:This method cannot be called on a + * PreparedStatement or CallableStatement. * @param sql any SQL statement * @return true if the first result is a ResultSet * object; false if it is an update count or there are * no results - * @exception SQLException if a database access error occurs or - * this method is called on a closed Statement + * @exception SQLException if a database access error occurs, + * this method is called on a closed Statement, + * the method is called on a + * PreparedStatement or CallableStatement + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} * @see #getResultSet * @see #getUpdateCount * @see #getMoreResults @@ -465,12 +497,14 @@ public interface Statement extends Wrapper { * Statement object. The commands in this list can be * executed as a batch by calling the method executeBatch. *

    - * + *Note:This method cannot be called on a + * PreparedStatement or CallableStatement. * @param sql typically this is a SQL INSERT or * UPDATE statement * @exception SQLException if a database access error occurs, - * this method is called on a closed Statement or the - * driver does not support batch updates + * this method is called on a closed Statement, the + * driver does not support batch updates, the method is called on a + * PreparedStatement or CallableStatement * @see #executeBatch * @see DatabaseMetaData#supportsBatchUpdates * @since 1.2 @@ -536,7 +570,10 @@ public interface Statement extends Wrapper { * driver does not support batch statements. Throws {@link BatchUpdateException} * (a subclass of SQLException) if one of the commands sent to the * database fails to execute properly or attempts to return a result set. - * + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} * * @see #addBatch * @see DatabaseMetaData#supportsBatchUpdates @@ -678,7 +715,9 @@ public interface Statement extends Wrapper { * flag if the SQL statement * is not an INSERT statement, or an SQL statement able to return * auto-generated keys (the list of such statements is vendor-specific). - * + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. * @param sql an SQL Data Manipulation Language (DML) statement, such as INSERT, UPDATE or * DELETE; or an SQL statement that returns nothing, * such as a DDL statement. @@ -693,10 +732,15 @@ public interface Statement extends Wrapper { * * @exception SQLException if a database access error occurs, * this method is called on a closed Statement, the given - * SQL statement returns a ResultSet object, or - * the given constant is not one of those allowed + * SQL statement returns a ResultSet object, + * the given constant is not one of those allowed, the method is called on a + * PreparedStatement or CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method with a constant of Statement.RETURN_GENERATED_KEYS + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} * @since 1.4 */ int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException; @@ -709,7 +753,9 @@ public interface Statement extends Wrapper { * available. The driver will ignore the array if the SQL statement * is not an INSERT statement, or an SQL statement able to return * auto-generated keys (the list of such statements is vendor-specific). - * + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. * @param sql an SQL Data Manipulation Language (DML) statement, such as INSERT, UPDATE or * DELETE; or an SQL statement that returns nothing, * such as a DDL statement. @@ -721,10 +767,15 @@ public interface Statement extends Wrapper { * * @exception SQLException if a database access error occurs, * this method is called on a closed Statement, the SQL - * statement returns a ResultSet object, or the - * second argument supplied to this method is not an int array - * whose elements are valid column indexes + * statement returns a ResultSet object,the second argument + * supplied to this method is not an + * int array whose elements are valid column indexes, the method is called on a + * PreparedStatement or CallableStatement * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} * @since 1.4 */ int executeUpdate(String sql, int columnIndexes[]) throws SQLException; @@ -737,7 +788,9 @@ public interface Statement extends Wrapper { * available. The driver will ignore the array if the SQL statement * is not an INSERT statement, or an SQL statement able to return * auto-generated keys (the list of such statements is vendor-specific). - * + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. * @param sql an SQL Data Manipulation Language (DML) statement, such as INSERT, UPDATE or * DELETE; or an SQL statement that returns nothing, * such as a DDL statement. @@ -748,11 +801,15 @@ public interface Statement extends Wrapper { * that return nothing * @exception SQLException if a database access error occurs, * this method is called on a closed Statement, the SQL - * statement returns a ResultSet object, or the + * statement returns a ResultSet object, the * second argument supplied to this method is not a String array - * whose elements are valid column names - * + * whose elements are valid column names, the method is called on a + * PreparedStatement or CallableStatement * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} * @since 1.4 */ int executeUpdate(String sql, String columnNames[]) throws SQLException; @@ -776,7 +833,9 @@ public interface Statement extends Wrapper { * getResultSet or getUpdateCount * to retrieve the result, and getMoreResults to * move to any subsequent result(s). - * + *

    + *Note:This method cannot be called on a + * PreparedStatement or CallableStatement. * @param sql any SQL statement * @param autoGeneratedKeys a constant indicating whether auto-generated * keys should be made available for retrieval using the method @@ -787,12 +846,18 @@ public interface Statement extends Wrapper { * object; false if it is an update count or there are * no results * @exception SQLException if a database access error occurs, - * this method is called on a closed Statement or the second + * this method is called on a closed Statement, the second * parameter supplied to this method is not * Statement.RETURN_GENERATED_KEYS or - * Statement.NO_GENERATED_KEYS. + * Statement.NO_GENERATED_KEYS, + * the method is called on a + * PreparedStatement or CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method with a constant of Statement.RETURN_GENERATED_KEYS + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} * @see #getResultSet * @see #getUpdateCount * @see #getMoreResults @@ -823,7 +888,9 @@ public interface Statement extends Wrapper { * getResultSet or getUpdateCount * to retrieve the result, and getMoreResults to * move to any subsequent result(s). - * + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. * @param sql any SQL statement * @param columnIndexes an array of the indexes of the columns in the * inserted row that should be made available for retrieval by a @@ -832,10 +899,15 @@ public interface Statement extends Wrapper { * object; false if it is an update count or there * are no results * @exception SQLException if a database access error occurs, - * this method is called on a closed Statement or the + * this method is called on a closed Statement, the * elements in the int array passed to this method - * are not valid column indexes + * are not valid column indexes, the method is called on a + * PreparedStatement or CallableStatement * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} * @see #getResultSet * @see #getUpdateCount * @see #getMoreResults @@ -865,7 +937,9 @@ public interface Statement extends Wrapper { * getResultSet or getUpdateCount * to retrieve the result, and getMoreResults to * move to any subsequent result(s). - * + *

    + * Note:This method cannot be called on a + * PreparedStatement or CallableStatement. * @param sql any SQL statement * @param columnNames an array of the names of the columns in the inserted * row that should be made available for retrieval by a call to the @@ -874,10 +948,15 @@ public interface Statement extends Wrapper { * object; false if it is an update count or there * are no more results * @exception SQLException if a database access error occurs, - * this method is called on a closed Statement or the + * this method is called on a closed Statement,the * elements of the String array passed to this - * method are not valid column names + * method are not valid column names, the method is called on a + * PreparedStatement or CallableStatement * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method + * @throws SQLTimeoutException when the driver has determined that the + * timeout value that was specified by the {@code setQueryTimeout} + * method has been exceeded and has at least attempted to cancel + * the currently running {@code Statement} * @see #getResultSet * @see #getUpdateCount * @see #getMoreResults @@ -951,4 +1030,34 @@ public interface Statement extends Wrapper { boolean isPoolable() throws SQLException; + //--------------------------JDBC 4.1 ----------------------------- + + /** + * Specifies that this {@code Statement} will be closed when all its + * dependent result sets are closed. If execution of the {@code Statement} + * does not produce any result sets, this method has no effect. + *

    + * Note: Multiple calls to {@code closeOnCompletion} do + * not toggle the effect on this {@code Statement}. However, a call to + * {@code closeOnCompletion} does effect both the subsequent execution of + * statements, and statements that currently have open, dependent, + * result sets. + * + * @throws SQLException if this method is called on a closed + * {@code Statement} + * @since 1.7 + */ + public void closeOnCompletion() throws SQLException; + + /** + * Returns a value indicating whether this {@code Statement} will be + * closed when all dependent objects such as resultsets are closed. + * @return {@code true} if the {@code Statement} will be closed when all + * of its dependent objects are closed; {@code false} otherwise + * @throws SQLException if this method is called on a closed + * {@code Statement} + * @since 1.7 + */ + public boolean isCloseOnCompletion() throws SQLException; + } diff --git a/jdk/src/share/classes/java/sql/Timestamp.java b/jdk/src/share/classes/java/sql/Timestamp.java index 4852d8d33af..411c04eb19e 100644 --- a/jdk/src/share/classes/java/sql/Timestamp.java +++ b/jdk/src/share/classes/java/sql/Timestamp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,19 +155,26 @@ public class Timestamp extends java.util.Date { * Converts a String object in JDBC timestamp escape format to a * Timestamp value. * - * @param s timestamp in format yyyy-mm-dd hh:mm:ss[.f...]. The - * fractional seconds may be omitted. + * @param s timestamp in format yyyy-[m]m-[d]d hh:mm:ss[.f...]. The + * fractional seconds may be omitted. The leading zero for mm + * and dd may also be omitted. + * * @return corresponding Timestamp value * @exception java.lang.IllegalArgumentException if the given argument - * does not have the format yyyy-mm-dd hh:mm:ss[.f...] + * does not have the format yyyy-[m]m-[d]d hh:mm:ss[.f...] */ public static Timestamp valueOf(String s) { + final int YEAR_LENGTH = 4; + final int MONTH_LENGTH = 2; + final int DAY_LENGTH = 2; + final int MAX_MONTH = 12; + final int MAX_DAY = 31; String date_s; String time_s; String nanos_s; - int year; - int month; - int day; + int year = 0; + int month = 0; + int day = 0; int hour; int minute; int second; @@ -182,17 +189,9 @@ public class Timestamp extends java.util.Date { String zeros = "000000000"; String delimiterDate = "-"; String delimiterTime = ":"; - StringTokenizer stringTokeninzerDate; - StringTokenizer stringTokeninzerTime; if (s == null) throw new java.lang.IllegalArgumentException("null string"); - int counterD = 0; - int intDate[] = {4,2,2}; - - int counterT = 0; - int intTime[] = {2,2,12}; - // Split the string into date and time components s = s.trim(); dividingSpace = s.indexOf(' '); @@ -203,30 +202,6 @@ public class Timestamp extends java.util.Date { throw new java.lang.IllegalArgumentException(formatError); } - stringTokeninzerTime = new StringTokenizer(time_s, delimiterTime); - stringTokeninzerDate = new StringTokenizer(date_s, delimiterDate); - - while(stringTokeninzerDate.hasMoreTokens()) { - String tokenDate = stringTokeninzerDate.nextToken(); - if(tokenDate.length() != intDate[counterD] ) { - throw new java.lang.IllegalArgumentException(formatError); - } - counterD++; - } - - /* - //Commenting this portion out for checking of time - - while(stringTokeninzerTime.hasMoreTokens()) { - String tokenTime = stringTokeninzerTime.nextToken(); - - if (counterT < 2 && tokenTime.length() != intTime[counterT] ) { - throw new java.lang.IllegalArgumentException(formatError); - } - counterT++; - } - */ - // Parse the date firstDash = date_s.indexOf('-'); secondDash = date_s.indexOf('-', firstDash+1); @@ -239,14 +214,24 @@ public class Timestamp extends java.util.Date { period = time_s.indexOf('.', secondColon+1); // Convert the date - if ((firstDash > 0) && (secondDash > 0) && - (secondDash < date_s.length()-1)) { - year = Integer.parseInt(date_s.substring(0, firstDash)) - 1900; - month = - Integer.parseInt(date_s.substring - (firstDash+1, secondDash)) - 1; - day = Integer.parseInt(date_s.substring(secondDash+1)); - } else { + boolean parsedDate = false; + if ((firstDash > 0) && (secondDash > 0) && (secondDash < date_s.length() - 1)) { + String yyyy = date_s.substring(0, firstDash); + String mm = date_s.substring(firstDash + 1, secondDash); + String dd = date_s.substring(secondDash + 1); + if (yyyy.length() == YEAR_LENGTH && + (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) && + (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) { + year = Integer.parseInt(yyyy); + month = Integer.parseInt(mm); + day = Integer.parseInt(dd); + + if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) { + parsedDate = true; + } + } + } + if (! parsedDate) { throw new java.lang.IllegalArgumentException(formatError); } @@ -272,10 +257,10 @@ public class Timestamp extends java.util.Date { second = Integer.parseInt(time_s.substring(secondColon+1)); } } else { - throw new java.lang.IllegalArgumentException(); + throw new java.lang.IllegalArgumentException(formatError); } - return new Timestamp(year, month, day, hour, minute, second, a_nanos); + return new Timestamp(year - 1900, month - 1, day, hour, minute, second, a_nanos); } /** @@ -502,14 +487,10 @@ public class Timestamp extends java.util.Date { /** * Compares this Timestamp object to the given - * Date, which must be a Timestamp - * object. If the argument is not a Timestamp object, - * this method throws a ClassCastException object. - * (Timestamp objects are - * comparable only to other Timestamp objects.) + * Date object. * - * @param o the Date to be compared, which must be a - * Timestamp object + * @param o the Date to be compared to + * this Timestamp object * @return the value 0 if this Timestamp object * and the given object are equal; a value less than 0 * if this Timestamp object is before the given argument; diff --git a/jdk/src/share/classes/java/text/CalendarBuilder.java b/jdk/src/share/classes/java/text/CalendarBuilder.java new file mode 100644 index 00000000000..0b73cd2ba90 --- /dev/null +++ b/jdk/src/share/classes/java/text/CalendarBuilder.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.text; + +import java.util.Calendar; +import static java.util.GregorianCalendar.*; + +/** + * {@code CalendarBuilder} keeps field-value pairs for setting + * the calendar fields of the given {@code Calendar}. It has the + * {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year + * support. Also {@code ISO_DAY_OF_WEEK} is used to specify + * {@code DAY_OF_WEEK} in the ISO day of week numbering. + * + *

    {@code CalendarBuilder} retains the semantic of the pseudo + * timestamp for fields. {@code CalendarBuilder} uses a single + * int array combining fields[] and stamp[] of {@code Calendar}. + * + * @author Masayoshi Okutsu + */ +class CalendarBuilder { + /* + * Pseudo time stamp constants used in java.util.Calendar + */ + private static final int UNSET = 0; + private static final int COMPUTED = 1; + private static final int MINIMUM_USER_STAMP = 2; + + private static final int MAX_FIELD = FIELD_COUNT + 1; + + public static final int WEEK_YEAR = FIELD_COUNT; + public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index + + // stamp[] (lower half) and field[] (upper half) combined + private final int[] field; + private int nextStamp; + private int maxFieldIndex; + + CalendarBuilder() { + field = new int[MAX_FIELD * 2]; + nextStamp = MINIMUM_USER_STAMP; + maxFieldIndex = -1; + } + + CalendarBuilder set(int index, int value) { + if (index == ISO_DAY_OF_WEEK) { + index = DAY_OF_WEEK; + value = toCalendarDayOfWeek(value); + } + field[index] = nextStamp++; + field[MAX_FIELD + index] = value; + if (index > maxFieldIndex && index < FIELD_COUNT) { + maxFieldIndex = index; + } + return this; + } + + CalendarBuilder addYear(int value) { + field[MAX_FIELD + YEAR] += value; + field[MAX_FIELD + WEEK_YEAR] += value; + return this; + } + + boolean isSet(int index) { + if (index == ISO_DAY_OF_WEEK) { + index = DAY_OF_WEEK; + } + return field[index] > UNSET; + } + + Calendar establish(Calendar cal) { + boolean weekDate = isSet(WEEK_YEAR) + && field[WEEK_YEAR] > field[YEAR]; + if (weekDate && !cal.isWeekDateSupported()) { + // Use YEAR instead + if (!isSet(YEAR)) { + set(YEAR, field[MAX_FIELD + WEEK_YEAR]); + } + weekDate = false; + } + + cal.clear(); + // Set the fields from the min stamp to the max stamp so that + // the field resolution works in the Calendar. + for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) { + for (int index = 0; index <= maxFieldIndex; index++) { + if (field[index] == stamp) { + cal.set(index, field[MAX_FIELD + index]); + break; + } + } + } + + if (weekDate) { + int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1; + int dayOfWeek = isSet(DAY_OF_WEEK) ? + field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek(); + if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) { + if (dayOfWeek >= 8) { + dayOfWeek--; + weekOfYear += dayOfWeek / 7; + dayOfWeek = (dayOfWeek % 7) + 1; + } else { + while (dayOfWeek <= 0) { + dayOfWeek += 7; + weekOfYear--; + } + } + dayOfWeek = toCalendarDayOfWeek(dayOfWeek); + } + cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek); + } + return cal; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("CalendarBuilder:["); + for (int i = 0; i < field.length; i++) { + if (isSet(i)) { + sb.append(i).append('=').append(field[MAX_FIELD + i]).append(','); + } + } + int lastIndex = sb.length() - 1; + if (sb.charAt(lastIndex) == ',') { + sb.setLength(lastIndex); + } + sb.append(']'); + return sb.toString(); + } + + static int toISODayOfWeek(int calendarDayOfWeek) { + return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1; + } + + static int toCalendarDayOfWeek(int isoDayOfWeek) { + if (!isValidDayOfWeek(isoDayOfWeek)) { + // adjust later for lenient mode + return isoDayOfWeek; + } + return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1; + } + + static boolean isValidDayOfWeek(int dayOfWeek) { + return dayOfWeek > 0 && dayOfWeek <= 7; + } +} diff --git a/jdk/src/share/classes/java/text/DateFormat.java b/jdk/src/share/classes/java/text/DateFormat.java index 8bc6d017dd8..fdd8eebea07 100644 --- a/jdk/src/share/classes/java/text/DateFormat.java +++ b/jdk/src/share/classes/java/text/DateFormat.java @@ -443,7 +443,7 @@ public abstract class DateFormat extends Format { */ public final static DateFormat getTimeInstance() { - return get(DEFAULT, 0, 1, Locale.getDefault()); + return get(DEFAULT, 0, 1, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -455,7 +455,7 @@ public abstract class DateFormat extends Format { */ public final static DateFormat getTimeInstance(int style) { - return get(style, 0, 1, Locale.getDefault()); + return get(style, 0, 1, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -479,7 +479,7 @@ public abstract class DateFormat extends Format { */ public final static DateFormat getDateInstance() { - return get(0, DEFAULT, 2, Locale.getDefault()); + return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -491,7 +491,7 @@ public abstract class DateFormat extends Format { */ public final static DateFormat getDateInstance(int style) { - return get(0, style, 2, Locale.getDefault()); + return get(0, style, 2, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -515,7 +515,7 @@ public abstract class DateFormat extends Format { */ public final static DateFormat getDateTimeInstance() { - return get(DEFAULT, DEFAULT, 3, Locale.getDefault()); + return get(DEFAULT, DEFAULT, 3, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -530,7 +530,7 @@ public abstract class DateFormat extends Format { public final static DateFormat getDateTimeInstance(int dateStyle, int timeStyle) { - return get(timeStyle, dateStyle, 3, Locale.getDefault()); + return get(timeStyle, dateStyle, 3, Locale.getDefault(Locale.Category.FORMAT)); } /** diff --git a/jdk/src/share/classes/java/text/DateFormatSymbols.java b/jdk/src/share/classes/java/text/DateFormatSymbols.java index 70b4955114a..4d6f08f4cac 100644 --- a/jdk/src/share/classes/java/text/DateFormatSymbols.java +++ b/jdk/src/share/classes/java/text/DateFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,7 +118,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { */ public DateFormatSymbols() { - initializeData(Locale.getDefault()); + initializeData(Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -226,7 +226,30 @@ public class DateFormatSymbols implements Serializable, Cloneable { * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. * All locales use the same these unlocalized pattern characters. */ - static final String patternChars = "GyMdkHmsSEDFwWahKzZ"; + static final String patternChars = "GyMdkHmsSEDFwWahKzZYuX"; + + static final int PATTERN_ERA = 0; // G + static final int PATTERN_YEAR = 1; // y + static final int PATTERN_MONTH = 2; // M + static final int PATTERN_DAY_OF_MONTH = 3; // d + static final int PATTERN_HOUR_OF_DAY1 = 4; // k + static final int PATTERN_HOUR_OF_DAY0 = 5; // H + static final int PATTERN_MINUTE = 6; // m + static final int PATTERN_SECOND = 7; // s + static final int PATTERN_MILLISECOND = 8; // S + static final int PATTERN_DAY_OF_WEEK = 9; // E + static final int PATTERN_DAY_OF_YEAR = 10; // D + static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F + static final int PATTERN_WEEK_OF_YEAR = 12; // w + static final int PATTERN_WEEK_OF_MONTH = 13; // W + static final int PATTERN_AM_PM = 14; // a + static final int PATTERN_HOUR1 = 15; // h + static final int PATTERN_HOUR0 = 16; // K + static final int PATTERN_ZONE_NAME = 17; // z + static final int PATTERN_ZONE_VALUE = 18; // Z + static final int PATTERN_WEEK_YEAR = 19; // Y + static final int PATTERN_ISO_DAY_OF_WEEK = 20; // u + static final int PATTERN_ISO_ZONE = 21; // X /** * Localized date-time pattern characters. For example, a locale may @@ -282,7 +305,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { * @since 1.6 */ public static final DateFormatSymbols getInstance() { - return getInstance(Locale.getDefault()); + return getInstance(Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -505,7 +528,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { * @return the localized date-time pattern characters. */ public String getLocalPatternChars() { - return new String(localPatternChars); + return localPatternChars; } /** @@ -514,7 +537,8 @@ public class DateFormatSymbols implements Serializable, Cloneable { * pattern characters. */ public void setLocalPatternChars(String newLocalPatternChars) { - localPatternChars = new String(newLocalPatternChars); + // Call toString() to throw an NPE in case the argument is null + localPatternChars = newLocalPatternChars.toString(); } /** @@ -699,7 +723,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { } else { dst.zoneStrings = null; } - dst.localPatternChars = new String (src.localPatternChars); + dst.localPatternChars = src.localPatternChars; } /** diff --git a/jdk/src/share/classes/java/text/DecimalFormat.java b/jdk/src/share/classes/java/text/DecimalFormat.java index 01bc8c5d02d..3a0d9b475bf 100644 --- a/jdk/src/share/classes/java/text/DecimalFormat.java +++ b/jdk/src/share/classes/java/text/DecimalFormat.java @@ -392,7 +392,7 @@ public class DecimalFormat extends NumberFormat { * @see java.text.NumberFormat#getPercentInstance */ public DecimalFormat() { - Locale def = Locale.getDefault(); + Locale def = Locale.getDefault(Locale.Category.FORMAT); // try to get the pattern from the cache String pattern = (String) cachedLocaleData.get(def); if (pattern == null) { /* cache miss */ @@ -430,7 +430,7 @@ public class DecimalFormat extends NumberFormat { */ public DecimalFormat(String pattern) { // Always applyPattern after the symbols are set - this.symbols = new DecimalFormatSymbols(Locale.getDefault()); + this.symbols = new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT)); applyPattern(pattern, false); } diff --git a/jdk/src/share/classes/java/text/DecimalFormatSymbols.java b/jdk/src/share/classes/java/text/DecimalFormatSymbols.java index d13d61320af..b3c55b82c20 100644 --- a/jdk/src/share/classes/java/text/DecimalFormatSymbols.java +++ b/jdk/src/share/classes/java/text/DecimalFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,10 +43,10 @@ import java.io.ObjectInputStream; import java.io.Serializable; import java.text.spi.DecimalFormatSymbolsProvider; import java.util.Currency; -import java.util.Hashtable; import java.util.Locale; import java.util.ResourceBundle; -import java.util.spi.LocaleServiceProvider; +import java.util.concurrent.ConcurrentHashMap; + import sun.util.LocaleServiceProviderPool; import sun.util.resources.LocaleData; @@ -76,7 +76,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { * {@link #getInstance(Locale) getInstance} method. */ public DecimalFormatSymbols() { - initialize( Locale.getDefault() ); + initialize( Locale.getDefault(Locale.Category.FORMAT) ); } /** @@ -125,7 +125,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { * @since 1.6 */ public static final DecimalFormatSymbols getInstance() { - return getInstance(Locale.getDefault()); + return getInstance(Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -527,10 +527,17 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { // get resource bundle data - try the cache first boolean needCacheUpdate = false; - Object[] data = (Object[]) cachedLocaleData.get(locale); + Object[] data = cachedLocaleData.get(locale); if (data == null) { /* cache miss */ + // When numbering system is thai (Locale's extension contains u-nu-thai), + // we read the data from th_TH_TH. + Locale lookupLocale = locale; + String numberType = locale.getUnicodeLocaleType("nu"); + if (numberType != null && numberType.equals("thai")) { + lookupLocale = new Locale("th", "TH", "TH"); + } data = new Object[3]; - ResourceBundle rb = LocaleData.getNumberFormatData(locale); + ResourceBundle rb = LocaleData.getNumberFormatData(lookupLocale); data[0] = rb.getStringArray("NumberElements"); needCacheUpdate = true; } @@ -586,7 +593,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { monetarySeparator = decimalSeparator; if (needCacheUpdate) { - cachedLocaleData.put(locale, data); + cachedLocaleData.putIfAbsent(locale, data); } } @@ -806,7 +813,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { * cache to hold the NumberElements and the Currency * of a Locale. */ - private static final Hashtable cachedLocaleData = new Hashtable(3); + private static final ConcurrentHashMap cachedLocaleData = new ConcurrentHashMap(3); /** * Obtains a DecimalFormatSymbols instance from a DecimalFormatSymbolsProvider diff --git a/jdk/src/share/classes/java/text/MessageFormat.java b/jdk/src/share/classes/java/text/MessageFormat.java index a0025985baa..ec5c7ff0d65 100644 --- a/jdk/src/share/classes/java/text/MessageFormat.java +++ b/jdk/src/share/classes/java/text/MessageFormat.java @@ -363,7 +363,7 @@ public class MessageFormat extends Format { * @exception IllegalArgumentException if the pattern is invalid */ public MessageFormat(String pattern) { - this.locale = Locale.getDefault(); + this.locale = Locale.getDefault(Locale.Category.FORMAT); applyPattern(pattern); } diff --git a/jdk/src/share/classes/java/text/NumberFormat.java b/jdk/src/share/classes/java/text/NumberFormat.java index fd4e92884fa..d80e4bcbd53 100644 --- a/jdk/src/share/classes/java/text/NumberFormat.java +++ b/jdk/src/share/classes/java/text/NumberFormat.java @@ -381,7 +381,7 @@ public abstract class NumberFormat extends Format { * {@link #getNumberInstance() getNumberInstance()}. */ public final static NumberFormat getInstance() { - return getInstance(Locale.getDefault(), NUMBERSTYLE); + return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE); } /** @@ -397,7 +397,7 @@ public abstract class NumberFormat extends Format { * Returns a general-purpose number format for the current default locale. */ public final static NumberFormat getNumberInstance() { - return getInstance(Locale.getDefault(), NUMBERSTYLE); + return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE); } /** @@ -420,7 +420,7 @@ public abstract class NumberFormat extends Format { * @since 1.4 */ public final static NumberFormat getIntegerInstance() { - return getInstance(Locale.getDefault(), INTEGERSTYLE); + return getInstance(Locale.getDefault(Locale.Category.FORMAT), INTEGERSTYLE); } /** @@ -443,7 +443,7 @@ public abstract class NumberFormat extends Format { * Returns a currency format for the current default locale. */ public final static NumberFormat getCurrencyInstance() { - return getInstance(Locale.getDefault(), CURRENCYSTYLE); + return getInstance(Locale.getDefault(Locale.Category.FORMAT), CURRENCYSTYLE); } /** @@ -457,7 +457,7 @@ public abstract class NumberFormat extends Format { * Returns a percentage format for the current default locale. */ public final static NumberFormat getPercentInstance() { - return getInstance(Locale.getDefault(), PERCENTSTYLE); + return getInstance(Locale.getDefault(Locale.Category.FORMAT), PERCENTSTYLE); } /** @@ -471,7 +471,7 @@ public abstract class NumberFormat extends Format { * Returns a scientific format for the current default locale. */ /*public*/ final static NumberFormat getScientificInstance() { - return getInstance(Locale.getDefault(), SCIENTIFICSTYLE); + return getInstance(Locale.getDefault(Locale.Category.FORMAT), SCIENTIFICSTYLE); } /** diff --git a/jdk/src/share/classes/java/text/SimpleDateFormat.java b/jdk/src/share/classes/java/text/SimpleDateFormat.java index 060e7bf642e..defd076ed21 100644 --- a/jdk/src/share/classes/java/text/SimpleDateFormat.java +++ b/jdk/src/share/classes/java/text/SimpleDateFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ import sun.util.calendar.CalendarUtils; import sun.util.calendar.ZoneInfoFile; import sun.util.resources.LocaleData; +import static java.text.DateFormatSymbols.*; + /** * SimpleDateFormat is a concrete class for formatting and * parsing dates in a locale-sensitive manner. It allows for formatting @@ -108,40 +110,50 @@ import sun.util.resources.LocaleData; * Year * 1996; 96 * + * Y + * Week year + * Year + * 2009; 09 + * * M * Month in year * Month * July; Jul; 07 - * + * * w * Week in year * Number * 27 - * + * * W * Week in month * Number * 2 - * + * * D * Day in year * Number * 189 - * + * * d * Day in month * Number * 10 - * + * * F * Day of week in month * Number * 2 - * + * * E - * Day in week + * Day name in week * Text * Tuesday; Tue + * + * u + * Day number of week (1 = Monday, ..., 7 = Sunday) + * Number + * 1 * * a * Am/pm marker @@ -192,6 +204,11 @@ import sun.util.resources.LocaleData; * Time zone * RFC 822 time zone * -0800 + * + * X + * Time zone + * ISO 8601 time zone + * -08; -0800; -08:00 * * * Pattern letters are usually repeated, as their number determines the @@ -202,12 +219,12 @@ import sun.util.resources.LocaleData; * the full form is used; otherwise a short or abbreviated form * is used if available. * For parsing, both forms are accepted, independent of the number - * of pattern letters. + * of pattern letters.

  • *
  • Number: * For formatting, the number of pattern letters is the minimum * number of digits, and shorter numbers are zero-padded to this amount. * For parsing, the number of pattern letters is ignored unless - * it's needed to separate two adjacent fields. + * it's needed to separate two adjacent fields.

  • *
  • Year: * If the formatter's {@link #getCalendar() Calendar} is the Gregorian * calendar, the following rules are applied.
    @@ -239,11 +256,20 @@ import sun.util.resources.LocaleData; * letters is 4 or more, a calendar specific {@linkplain * Calendar#LONG long form} is used. Otherwise, a calendar * specific {@linkplain Calendar#SHORT short or abbreviated form} - * is used. + * is used.
    + *
    + * If week year {@code 'Y'} is specified and the {@linkplain + * #getCalendar() calendar} doesn't support any week + * years, the calendar year ({@code 'y'}) is used instead. The + * support of week years can be tested with a call to {@link + * DateFormat#getCalendar() getCalendar()}.{@link + * java.util.Calendar#isWeekDateSupported() + * isWeekDateSupported()}.

  • *
  • Month: * If the number of pattern letters is 3 or more, the month is * interpreted as text; otherwise, - * it is interpreted as a number. + * it is interpreted as a number.

  • *
  • General time zone: * Time zones are interpreted as text if they have * names. For time zones representing a GMT offset value, the @@ -264,9 +290,10 @@ import sun.util.resources.LocaleData; * 00 and 59. The format is locale independent and digits must be taken * from the Basic Latin block of the Unicode standard. *

    For parsing, RFC 822 time zones are also - * accepted. + * accepted.

  • *
  • RFC 822 time zone: * For formatting, the RFC 822 4-digit time zone format is used: + * *
      *     RFC822TimeZone:
      *             Sign TwoDigitHours Minutes
    @@ -274,8 +301,41 @@ import sun.util.resources.LocaleData;
      *             Digit Digit
    * TwoDigitHours must be between 00 and 23. Other definitions * are as for general time zones. + * *

    For parsing, general time zones are also * accepted. + *

  • ISO 8601 Time zone: + * The number of pattern letters designates the format for both formatting + * and parsing as follows: + *
    + *     ISO8601TimeZone:
    + *             OneLetterISO8601TimeZone
    + *             TwoLetterISO8601TimeZone
    + *             ThreeLetterISO8601TimeZone
    + *     OneLetterISO8601TimeZone:
    + *             Sign TwoDigitHours
    + *             {@code Z}
    + *     TwoLetterISO8601TimeZone:
    + *             Sign TwoDigitHours Minutes
    + *             {@code Z}
    + *     ThreeLetterISO8601TimeZone:
    + *             Sign TwoDigitHours {@code :} Minutes
    + *             {@code Z}
    + * Other definitions are as for general time zones or + * RFC 822 time zones. + * + *

    For formatting, if the offset value from GMT is 0, {@code "Z"} is + * produced. If the number of pattern letters is 1, any fraction of an hour + * is ignored. For example, if the pattern is {@code "X"} and the time zone is + * {@code "GMT+05:30"}, {@code "+05"} is produced. + * + *

    For parsing, {@code "Z"} is parsed as the UTC time zone designator. + * General time zones are not accepted. + * + *

    If the number of pattern letters is 4 or more, {@link + * IllegalArgumentException} is thrown when constructing a {@code + * SimpleDateFormat} or {@linkplain #applyPattern(String) applying a + * pattern}. * * SimpleDateFormat also supports localized date and time * pattern strings. In these strings, the pattern letters described above @@ -321,6 +381,12 @@ import sun.util.resources.LocaleData; * * "yyyy-MM-dd'T'HH:mm:ss.SSSZ" * 2001-07-04T12:08:56.235-0700 + * + * "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" + * 2001-07-04T12:08:56.235-07:00 + * + * "YYYY-'W'ww-u" + * 2001-W27-3 * * * @@ -474,7 +540,7 @@ public class SimpleDateFormat extends DateFormat { * class. */ public SimpleDateFormat() { - this(SHORT, SHORT, Locale.getDefault()); + this(SHORT, SHORT, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -490,7 +556,7 @@ public class SimpleDateFormat extends DateFormat { */ public SimpleDateFormat(String pattern) { - this(pattern, Locale.getDefault()); + this(pattern, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -535,7 +601,7 @@ public class SimpleDateFormat extends DateFormat { this.pattern = pattern; this.formatData = (DateFormatSymbols) formatSymbols.clone(); - this.locale = Locale.getDefault(); + this.locale = Locale.getDefault(Locale.Category.FORMAT); initializeCalendar(this.locale); initialize(this.locale); useDateFormatSymbols = true; @@ -815,6 +881,9 @@ public class SimpleDateFormat extends DateFormat { * Encodes the given tag and length and puts encoded char(s) into buffer. */ private static final void encode(int tag, int length, StringBuilder buffer) { + if (tag == PATTERN_ISO_ZONE && length >= 4) { + throw new IllegalArgumentException("invalid ISO 8601 format: length=" + length); + } if (length < 255) { buffer.append((char)(tag << 8 | length)); } else { @@ -877,7 +946,7 @@ public class SimpleDateFormat extends DateFormat { * @param pos the formatting position. On input: an alignment field, * if desired. On output: the offsets of the alignment field. * @return the formatted date-time string. - * @exception NullPointerException if the given date is null + * @exception NullPointerException if the given {@code date} is {@code null}. */ public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) @@ -968,6 +1037,10 @@ public class SimpleDateFormat extends DateFormat { Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK_IN_MONTH, Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH, Calendar.AM_PM, Calendar.HOUR, Calendar.HOUR, Calendar.ZONE_OFFSET, + Calendar.ZONE_OFFSET, + // Pseudo Calendar fields + CalendarBuilder.WEEK_YEAR, + CalendarBuilder.ISO_DAY_OF_WEEK, Calendar.ZONE_OFFSET }; @@ -982,6 +1055,8 @@ public class SimpleDateFormat extends DateFormat { DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.AM_PM_FIELD, DateFormat.HOUR1_FIELD, DateFormat.HOUR0_FIELD, DateFormat.TIMEZONE_FIELD, DateFormat.TIMEZONE_FIELD, + DateFormat.YEAR_FIELD, DateFormat.DAY_OF_WEEK_FIELD, + DateFormat.TIMEZONE_FIELD }; // Maps from DecimalFormatSymbols index to Field constant @@ -993,6 +1068,8 @@ public class SimpleDateFormat extends DateFormat { Field.WEEK_OF_YEAR, Field.WEEK_OF_MONTH, Field.AM_PM, Field.HOUR1, Field.HOUR0, Field.TIME_ZONE, Field.TIME_ZONE, + Field.YEAR, Field.DAY_OF_WEEK, + Field.TIME_ZONE }; /** @@ -1007,9 +1084,24 @@ public class SimpleDateFormat extends DateFormat { int beginOffset = buffer.length(); int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex]; - int value = calendar.get(field); + int value; + if (field == CalendarBuilder.WEEK_YEAR) { + if (calendar.isWeekDateSupported()) { + value = calendar.getWeekYear(); + } else { + // use calendar year 'y' instead + patternCharIndex = PATTERN_YEAR; + field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex]; + value = calendar.get(field); + } + } else if (field == CalendarBuilder.ISO_DAY_OF_WEEK) { + value = CalendarBuilder.toISODayOfWeek(calendar.get(Calendar.DAY_OF_WEEK)); + } else { + value = calendar.get(field); + } + int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT; - if (!useDateFormatSymbols) { + if (!useDateFormatSymbols && field != CalendarBuilder.ISO_DAY_OF_WEEK) { current = calendar.getDisplayName(field, style, locale); } @@ -1018,7 +1110,7 @@ public class SimpleDateFormat extends DateFormat { // zeroPaddingNumber() must be fixed. switch (patternCharIndex) { - case 0: // 'G' - ERA + case PATTERN_ERA: // 'G' if (useDateFormatSymbols) { String[] eras = formatData.getEras(); if (value < eras.length) @@ -1028,7 +1120,8 @@ public class SimpleDateFormat extends DateFormat { current = ""; break; - case 1: // 'y' - YEAR + case PATTERN_WEEK_YEAR: // 'Y' + case PATTERN_YEAR: // 'y' if (calendar instanceof GregorianCalendar) { if (count != 2) zeroPaddingNumber(value, count, maxIntCount, buffer); @@ -1042,7 +1135,7 @@ public class SimpleDateFormat extends DateFormat { } break; - case 2: // 'M' - MONTH + case PATTERN_MONTH: // 'M' if (useDateFormatSymbols) { String[] months; if (count >= 4) { @@ -1062,7 +1155,7 @@ public class SimpleDateFormat extends DateFormat { } break; - case 4: // 'k' - HOUR_OF_DAY: 1-based. eg, 23:59 + 1 hour =>> 24:59 + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59 if (current == null) { if (value == 0) zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY)+1, @@ -1072,7 +1165,7 @@ public class SimpleDateFormat extends DateFormat { } break; - case 9: // 'E' - DAY_OF_WEEK + case PATTERN_DAY_OF_WEEK: // 'E' if (useDateFormatSymbols) { String[] weekdays; if (count >= 4) { @@ -1085,14 +1178,14 @@ public class SimpleDateFormat extends DateFormat { } break; - case 14: // 'a' - AM_PM + case PATTERN_AM_PM: // 'a' if (useDateFormatSymbols) { String[] ampm = formatData.getAmPmStrings(); current = ampm[value]; } break; - case 15: // 'h' - HOUR:1-based. eg, 11PM + 1 hour =>> 12 AM + case PATTERN_HOUR1: // 'h' 1-based. eg, 11PM + 1 hour =>> 12 AM if (current == null) { if (value == 0) zeroPaddingNumber(calendar.getLeastMaximum(Calendar.HOUR)+1, @@ -1102,7 +1195,7 @@ public class SimpleDateFormat extends DateFormat { } break; - case 17: // 'z' - ZONE_OFFSET + case PATTERN_ZONE_NAME: // 'z' if (current == null) { if (formatData.locale == null || formatData.isZoneStringsSet) { int zoneIndex = @@ -1129,7 +1222,7 @@ public class SimpleDateFormat extends DateFormat { } break; - case 18: // 'Z' - ZONE_OFFSET ("-/+hhmm" form) + case PATTERN_ZONE_VALUE: // 'Z' ("-/+hhmm" form) value = (calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)) / 60000; @@ -1144,17 +1237,46 @@ public class SimpleDateFormat extends DateFormat { CalendarUtils.sprintf0d(buffer, num, width); break; + case PATTERN_ISO_ZONE: // 'X' + value = calendar.get(Calendar.ZONE_OFFSET) + + calendar.get(Calendar.DST_OFFSET); + + if (value == 0) { + buffer.append('Z'); + break; + } + + value /= 60000; + if (value >= 0) { + buffer.append('+'); + } else { + buffer.append('-'); + value = -value; + } + + CalendarUtils.sprintf0d(buffer, value / 60, 2); + if (count == 1) { + break; + } + + if (count == 3) { + buffer.append(':'); + } + CalendarUtils.sprintf0d(buffer, value % 60, 2); + break; + default: - // case 3: // 'd' - DATE - // case 5: // 'H' - HOUR_OF_DAY:0-based. eg, 23:59 + 1 hour =>> 00:59 - // case 6: // 'm' - MINUTE - // case 7: // 's' - SECOND - // case 8: // 'S' - MILLISECOND - // case 10: // 'D' - DAY_OF_YEAR - // case 11: // 'F' - DAY_OF_WEEK_IN_MONTH - // case 12: // 'w' - WEEK_OF_YEAR - // case 13: // 'W' - WEEK_OF_MONTH - // case 16: // 'K' - HOUR: 0-based. eg, 11PM + 1 hour =>> 0 AM + // case PATTERN_DAY_OF_MONTH: // 'd' + // case PATTERN_HOUR_OF_DAY0: // 'H' 0-based. eg, 23:59 + 1 hour =>> 00:59 + // case PATTERN_MINUTE: // 'm' + // case PATTERN_SECOND: // 's' + // case PATTERN_MILLISECOND: // 'S' + // case PATTERN_DAY_OF_YEAR: // 'D' + // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F' + // case PATTERN_WEEK_OF_YEAR: // 'w' + // case PATTERN_WEEK_OF_MONTH: // 'W' + // case PATTERN_HOUR0: // 'K' eg, 11PM + 1 hour =>> 0 AM + // case PATTERN_ISO_DAY_OF_WEEK: // 'u' pseudo field, Monday = 1, ..., Sunday = 7 if (current == null) { zeroPaddingNumber(value, count, maxIntCount, buffer); } @@ -1264,10 +1386,9 @@ public class SimpleDateFormat extends DateFormat { int oldStart = start; int textLength = text.length(); - calendar.clear(); // Clears all the time fields - boolean[] ambiguousYear = {false}; + CalendarBuilder calb = new CalendarBuilder(); for (int i = 0; i < compiledPattern.length; ) { int tag = compiledPattern[i] >>> 8; @@ -1340,7 +1461,7 @@ public class SimpleDateFormat extends DateFormat { } start = subParse(text, start, tag, count, obeyCount, ambiguousYear, pos, - useFollowingMinusSignAsDelimiter); + useFollowingMinusSignAsDelimiter, calb); if (start < 0) { pos.index = oldStart; return null; @@ -1354,46 +1475,16 @@ public class SimpleDateFormat extends DateFormat { pos.index = start; - // This part is a problem: When we call parsedDate.after, we compute the time. - // Take the date April 3 2004 at 2:30 am. When this is first set up, the year - // will be wrong if we're parsing a 2-digit year pattern. It will be 1904. - // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day. 2:30 am - // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am - // on that day. It is therefore parsed out to fields as 3:30 am. Then we - // add 100 years, and get April 3 2004 at 3:30 am. Note that April 3 2004 is - // a Saturday, so it can have a 2:30 am -- and it should. [LIU] - /* - Date parsedDate = calendar.getTime(); - if( ambiguousYear[0] && !parsedDate.after(defaultCenturyStart) ) { - calendar.add(Calendar.YEAR, 100); - parsedDate = calendar.getTime(); - } - */ - // Because of the above condition, save off the fields in case we need to readjust. - // The procedure we use here is not particularly efficient, but there is no other - // way to do this given the API restrictions present in Calendar. We minimize - // inefficiency by only performing this computation when it might apply, that is, - // when the two-digit year is equal to the start year, and thus might fall at the - // front or the back of the default century. This only works because we adjust - // the year correctly to start with in other cases -- see subParse(). Date parsedDate; try { - if (ambiguousYear[0]) // If this is true then the two-digit year == the default start year - { - // We need a copy of the fields, and we need to avoid triggering a call to - // complete(), which will recalculate the fields. Since we can't access - // the fields[] array in Calendar, we clone the entire object. This will - // stop working if Calendar.clone() is ever rewritten to call complete(). - Calendar savedCalendar = (Calendar)calendar.clone(); - parsedDate = calendar.getTime(); - if (parsedDate.before(defaultCenturyStart)) - { - // We can't use add here because that does a complete() first. - savedCalendar.set(Calendar.YEAR, defaultCenturyStartYear + 100); - parsedDate = savedCalendar.getTime(); + parsedDate = calb.establish(calendar).getTime(); + // If the year value is ambiguous, + // then the two-digit year == the default start year + if (ambiguousYear[0]) { + if (parsedDate.before(defaultCenturyStart)) { + parsedDate = calb.addYear(100).establish(calendar).getTime(); } } - else parsedDate = calendar.getTime(); } // An IllegalArgumentException will be thrown by Calendar.getTime() // if any fields are out of range, e.g., MONTH == 17. @@ -1415,7 +1506,7 @@ public class SimpleDateFormat extends DateFormat { * @return the new start position if matching succeeded; a negative number * indicating matching failure, otherwise. */ - private int matchString(String text, int start, int field, String[] data) + private int matchString(String text, int start, int field, String[] data, CalendarBuilder calb) { int i = 0; int count = data.length; @@ -1441,7 +1532,7 @@ public class SimpleDateFormat extends DateFormat { } if (bestMatch >= 0) { - calendar.set(field, bestMatch); + calb.set(field, bestMatch); return start + bestMatchLength; } return -start; @@ -1452,7 +1543,8 @@ public class SimpleDateFormat extends DateFormat { * String[]). This method takes a Map instead of * String[]. */ - private int matchString(String text, int start, int field, Map data) { + private int matchString(String text, int start, int field, + Map data, CalendarBuilder calb) { if (data != null) { String bestMatch = null; @@ -1466,7 +1558,7 @@ public class SimpleDateFormat extends DateFormat { } if (bestMatch != null) { - calendar.set(field, data.get(bestMatch)); + calb.set(field, data.get(bestMatch)); return start + bestMatch.length(); } } @@ -1486,11 +1578,22 @@ public class SimpleDateFormat extends DateFormat { return -1; } + private boolean matchDSTString(String text, int start, int zoneIndex, int standardIndex, + String[][] zoneStrings) { + int index = standardIndex + 2; + String zoneName = zoneStrings[zoneIndex][index]; + if (text.regionMatches(true, start, + zoneName, 0, zoneName.length())) { + return true; + } + return false; + } + /** * find time zone 'text' matched zoneStrings and set to internal * calendar. */ - private int subParseZoneString(String text, int start) { + private int subParseZoneString(String text, int start, CalendarBuilder calb) { boolean useSameName = false; // true if standard and daylight time use the same abbreviation. TimeZone currentTimeZone = getTimeZone(); @@ -1524,6 +1627,7 @@ public class SimpleDateFormat extends DateFormat { } } } + if (tz == null) { int len = zoneStrings.length; for (int i = 0; i < len; i++) { @@ -1549,8 +1653,8 @@ public class SimpleDateFormat extends DateFormat { // determine the local time. (6645292) int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0; if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) { - calendar.set(Calendar.ZONE_OFFSET, tz.getRawOffset()); - calendar.set(Calendar.DST_OFFSET, dstAmount); + calb.set(Calendar.ZONE_OFFSET, tz.getRawOffset()) + .set(Calendar.DST_OFFSET, dstAmount); } return (start + zoneNames[nameIndex].length()); } @@ -1577,11 +1681,15 @@ public class SimpleDateFormat extends DateFormat { private int subParse(String text, int start, int patternCharIndex, int count, boolean obeyCount, boolean[] ambiguousYear, ParsePosition origPos, - boolean useFollowingMinusSignAsDelimiter) { + boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) { Number number = null; int value = 0; ParsePosition pos = new ParsePosition(0); pos.index = start; + if (patternCharIndex == PATTERN_WEEK_YEAR && !calendar.isWeekDateSupported()) { + // use calendar year 'y' instead + patternCharIndex = PATTERN_YEAR; + } int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex]; // If there are any spaces here, skip over them. If we hit the end @@ -1602,10 +1710,11 @@ public class SimpleDateFormat extends DateFormat { // a number value. We handle further, more generic cases below. We need // to handle some of them here because some fields require extra processing on // the parsed value. - if (patternCharIndex == 4 /* HOUR_OF_DAY1_FIELD */ || - patternCharIndex == 15 /* HOUR1_FIELD */ || - (patternCharIndex == 2 /* MONTH_FIELD */ && count <= 2) || - patternCharIndex == 1 /* YEAR_FIELD */) { + if (patternCharIndex == PATTERN_HOUR_OF_DAY1 || + patternCharIndex == PATTERN_HOUR1 || + (patternCharIndex == PATTERN_MONTH && count <= 2) || + patternCharIndex == PATTERN_YEAR || + patternCharIndex == PATTERN_WEEK_YEAR) { // It would be good to unify this with the obeyCount logic below, // but that's going to be difficult. if (obeyCount) { @@ -1617,7 +1726,7 @@ public class SimpleDateFormat extends DateFormat { number = numberFormat.parse(text, pos); } if (number == null) { - if (patternCharIndex != 1 || calendar instanceof GregorianCalendar) { + if (patternCharIndex != PATTERN_YEAR || calendar instanceof GregorianCalendar) { break parsing; } } else { @@ -1638,33 +1747,34 @@ public class SimpleDateFormat extends DateFormat { int index; switch (patternCharIndex) { - case 0: // 'G' - ERA + case PATTERN_ERA: // 'G' if (useDateFormatSymbols) { - if ((index = matchString(text, start, Calendar.ERA, formatData.getEras())) > 0) { + if ((index = matchString(text, start, Calendar.ERA, formatData.getEras(), calb)) > 0) { return index; } } else { Map map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale); - if ((index = matchString(text, start, field, map)) > 0) { + if ((index = matchString(text, start, field, map, calb)) > 0) { return index; } } break parsing; - case 1: // 'y' - YEAR + case PATTERN_WEEK_YEAR: // 'Y' + case PATTERN_YEAR: // 'y' if (!(calendar instanceof GregorianCalendar)) { // calendar might have text representations for year values, // such as "\u5143" in JapaneseImperialCalendar. int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT; Map map = calendar.getDisplayNames(field, style, locale); if (map != null) { - if ((index = matchString(text, start, field, map)) > 0) { + if ((index = matchString(text, start, field, map, calb)) > 0) { return index; } } - calendar.set(field, value); + calb.set(field, value); return pos.index; } @@ -1676,8 +1786,7 @@ public class SimpleDateFormat extends DateFormat { // is treated literally: "2250", "-1", "1", "002". if (count <= 2 && (pos.index - start) == 2 && Character.isDigit(text.charAt(start)) - && Character.isDigit(text.charAt(start+1))) - { + && Character.isDigit(text.charAt(start+1))) { // Assume for example that the defaultCenturyStart is 6/18/1903. // This means that two-digit years will be forced into the range // 6/18/1903 to 6/17/2003. As a result, years 00, 01, and 02 @@ -1691,16 +1800,16 @@ public class SimpleDateFormat extends DateFormat { value += (defaultCenturyStartYear/100)*100 + (value < ambiguousTwoDigitYear ? 100 : 0); } - calendar.set(Calendar.YEAR, value); + calb.set(field, value); return pos.index; - case 2: // 'M' - MONTH + case PATTERN_MONTH: // 'M' if (count <= 2) // i.e., M or MM. { // Don't want to parse the month if it is a string // while pattern uses numeric style: M or MM. // [We computed 'value' above.] - calendar.set(Calendar.MONTH, value - 1); + calb.set(Calendar.MONTH, value - 1); return pos.index; } @@ -1710,50 +1819,50 @@ public class SimpleDateFormat extends DateFormat { // Try count == 4 first: int newStart = 0; if ((newStart = matchString(text, start, Calendar.MONTH, - formatData.getMonths())) > 0) { + formatData.getMonths(), calb)) > 0) { return newStart; } // count == 4 failed, now try count == 3 if ((index = matchString(text, start, Calendar.MONTH, - formatData.getShortMonths())) > 0) { + formatData.getShortMonths(), calb)) > 0) { return index; } } else { Map map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale); - if ((index = matchString(text, start, field, map)) > 0) { + if ((index = matchString(text, start, field, map, calb)) > 0) { return index; } } break parsing; - case 4: // 'k' - HOUR_OF_DAY: 1-based. eg, 23:59 + 1 hour =>> 24:59 + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59 // [We computed 'value' above.] if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY)+1) value = 0; - calendar.set(Calendar.HOUR_OF_DAY, value); + calb.set(Calendar.HOUR_OF_DAY, value); return pos.index; - case 9: - { // 'E' - DAY_OF_WEEK + case PATTERN_DAY_OF_WEEK: // 'E' + { if (useDateFormatSymbols) { // Want to be able to parse both short and long forms. // Try count == 4 (DDDD) first: int newStart = 0; if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK, - formatData.getWeekdays())) > 0) { + formatData.getWeekdays(), calb)) > 0) { return newStart; } // DDDD failed, now try DDD if ((index = matchString(text, start, Calendar.DAY_OF_WEEK, - formatData.getShortWeekdays())) > 0) { + formatData.getShortWeekdays(), calb)) > 0) { return index; } } else { int[] styles = { Calendar.LONG, Calendar.SHORT }; for (int style : styles) { Map map = calendar.getDisplayNames(field, style, locale); - if ((index = matchString(text, start, field, map)) > 0) { + if ((index = matchString(text, start, field, map, calb)) > 0) { return index; } } @@ -1761,27 +1870,28 @@ public class SimpleDateFormat extends DateFormat { } break parsing; - case 14: // 'a' - AM_PM + case PATTERN_AM_PM: // 'a' if (useDateFormatSymbols) { - if ((index = matchString(text, start, Calendar.AM_PM, formatData.getAmPmStrings())) > 0) { + if ((index = matchString(text, start, Calendar.AM_PM, + formatData.getAmPmStrings(), calb)) > 0) { return index; } } else { Map map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale); - if ((index = matchString(text, start, field, map)) > 0) { + if ((index = matchString(text, start, field, map, calb)) > 0) { return index; } } break parsing; - case 15: // 'h' - HOUR:1-based. eg, 11PM + 1 hour =>> 12 AM + case PATTERN_HOUR1: // 'h' 1-based. eg, 11PM + 1 hour =>> 12 AM // [We computed 'value' above.] if (value == calendar.getLeastMaximum(Calendar.HOUR)+1) value = 0; - calendar.set(Calendar.HOUR, value); + calb.set(Calendar.HOUR, value); return pos.index; - case 17: // 'z' - ZONE_OFFSET - case 18: // 'Z' - ZONE_OFFSET + case PATTERN_ZONE_NAME: // 'z' + case PATTERN_ZONE_VALUE: // 'Z' // First try to parse generic forms such as GMT-07:00. Do this first // in case localized TimeZoneNames contains the string "GMT" // for a zone; in that case, we don't want to match the first three @@ -1797,7 +1907,7 @@ public class SimpleDateFormat extends DateFormat { if ((text.length() - start) >= GMT.length() && text.regionMatches(true, start, GMT, 0, GMT.length())) { int num; - calendar.set(Calendar.DST_OFFSET, 0); + calb.set(Calendar.DST_OFFSET, 0); pos.index = start + GMT.length(); try { // try-catch for "GMT" only time zone string @@ -1810,8 +1920,8 @@ public class SimpleDateFormat extends DateFormat { } catch(StringIndexOutOfBoundsException e) {} - if (sign == 0) { /* "GMT" without offset */ - calendar.set(Calendar.ZONE_OFFSET, 0); + if (sign == 0) { /* "GMT" without offset */ + calb.set(Calendar.ZONE_OFFSET, 0); return pos.index; } @@ -1875,7 +1985,7 @@ public class SimpleDateFormat extends DateFormat { sign = -1; } else { // Try parsing the text as a time zone name (abbr). - int i = subParseZoneString(text, pos.index); + int i = subParseZoneString(text, pos.index, calb); if (i != 0) { return i; } @@ -1933,24 +2043,112 @@ public class SimpleDateFormat extends DateFormat { // arrive here if the form GMT+/-... or an RFC 822 form was seen. if (sign != 0) { offset *= MILLIS_PER_MINUTE * sign; - calendar.set(Calendar.ZONE_OFFSET, offset); - calendar.set(Calendar.DST_OFFSET, 0); + calb.set(Calendar.ZONE_OFFSET, offset).set(Calendar.DST_OFFSET, 0); + return ++pos.index; + } + } + break parsing; + + case PATTERN_ISO_ZONE: // 'X' + { + int sign = 0; + int offset = 0; + + iso8601: { + try { + char c = text.charAt(pos.index); + if (c == 'Z') { + calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0); + return ++pos.index; + } + + // parse text as "+/-hh[[:]mm]" based on count + if (c == '+') { + sign = 1; + } else if (c == '-') { + sign = -1; + } + // Look for hh. + int hours = 0; + c = text.charAt(++pos.index); + if (c < '0' || c > '9') { /* must be from '0' to '9'. */ + break parsing; + } + hours = c - '0'; + c = text.charAt(++pos.index); + if (c < '0' || c > '9') { /* must be from '0' to '9'. */ + break parsing; + } + hours *= 10; + hours += c - '0'; + if (hours > 23) { + break parsing; + } + + if (count == 1) { // "X" + offset = hours * 60; + break iso8601; + } + + c = text.charAt(++pos.index); + // Skip ':' if "XXX" + if (c == ':') { + if (count == 2) { + break parsing; + } + c = text.charAt(++pos.index); + } else { + if (count == 3) { + // missing ':' + break parsing; + } + } + + // Look for mm. + int minutes = 0; + if (c < '0' || c > '9') { /* must be from '0' to '9'. */ + break parsing; + } + minutes = c - '0'; + c = text.charAt(++pos.index); + if (c < '0' || c > '9') { /* must be from '0' to '9'. */ + break parsing; + } + minutes *= 10; + minutes += c - '0'; + + if (minutes > 59) { + break parsing; + } + + offset = hours * 60 + minutes; + } catch (StringIndexOutOfBoundsException e) { + break parsing; + } + } + + // Do the final processing for both of the above cases. We only + // arrive here if the form GMT+/-... or an RFC 822 form was seen. + if (sign != 0) { + offset *= MILLIS_PER_MINUTE * sign; + calb.set(Calendar.ZONE_OFFSET, offset).set(Calendar.DST_OFFSET, 0); return ++pos.index; } } break parsing; default: - // case 3: // 'd' - DATE - // case 5: // 'H' - HOUR_OF_DAY:0-based. eg, 23:59 + 1 hour =>> 00:59 - // case 6: // 'm' - MINUTE - // case 7: // 's' - SECOND - // case 8: // 'S' - MILLISECOND - // case 10: // 'D' - DAY_OF_YEAR - // case 11: // 'F' - DAY_OF_WEEK_IN_MONTH - // case 12: // 'w' - WEEK_OF_YEAR - // case 13: // 'W' - WEEK_OF_MONTH - // case 16: // 'K' - HOUR: 0-based. eg, 11PM + 1 hour =>> 0 AM + // case PATTERN_DAY_OF_MONTH: // 'd' + // case PATTERN_HOUR_OF_DAY0: // 'H' 0-based. eg, 23:59 + 1 hour =>> 00:59 + // case PATTERN_MINUTE: // 'm' + // case PATTERN_SECOND: // 's' + // case PATTERN_MILLISECOND: // 'S' + // case PATTERN_DAY_OF_YEAR: // 'D' + // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F' + // case PATTERN_WEEK_OF_YEAR: // 'w' + // case PATTERN_WEEK_OF_MONTH: // 'W' + // case PATTERN_HOUR0: // 'K' 0-based. eg, 11PM + 1 hour =>> 0 AM + // case PATTERN_ISO_DAY_OF_WEEK: // 'u' (pseudo field); // Handle "generic" fields if (obeyCount) { @@ -1973,7 +2171,7 @@ public class SimpleDateFormat extends DateFormat { pos.index--; } - calendar.set(field, value); + calb.set(field, value); return pos.index; } break parsing; @@ -2020,11 +2218,18 @@ public class SimpleDateFormat extends DateFormat { inQuote = true; else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { int ci = from.indexOf(c); - if (ci == -1) + if (ci >= 0) { + // patternChars is longer than localPatternChars due + // to serialization compatibility. The pattern letters + // unsupported by localPatternChars pass through. + if (ci < to.length()) { + c = to.charAt(ci); + } + } else { throw new IllegalArgumentException("Illegal pattern " + " character '" + c + "'"); - c = to.charAt(ci); + } } } result.append(c); @@ -2061,7 +2266,7 @@ public class SimpleDateFormat extends DateFormat { * @exception NullPointerException if the given pattern is null * @exception IllegalArgumentException if the given pattern is invalid */ - public void applyPattern (String pattern) + public void applyPattern(String pattern) { compiledPattern = compile(pattern); this.pattern = pattern; diff --git a/jdk/src/share/classes/java/util/Calendar.java b/jdk/src/share/classes/java/util/Calendar.java index 80a193687d0..7ec5e87ec39 100644 --- a/jdk/src/share/classes/java/util/Calendar.java +++ b/jdk/src/share/classes/java/util/Calendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,7 +119,7 @@ import sun.util.resources.LocaleData; * calculating its time or calendar field values if any out-of-range field * value has been set. * - *

    First Week

    + *

    First Week

    * * Calendar defines a locale-specific seven day week using two * parameters: the first day of the week and the minimal days in first week @@ -933,7 +933,7 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableThe default implementation of this method returns {@code false}. + * + * @return {@code true} if this {@code Calendar} supports week dates; + * {@code false} otherwise. + * @see #getWeekYear() + * @see #setWeekDate(int,int,int) + * @see #getWeeksInWeekYear() + * @since 1.7 + */ + public boolean isWeekDateSupported() { + return false; + } + + /** + * Returns the week year represented by this {@code Calendar}. The + * week year is in sync with the week cycle. The {@linkplain + * #getFirstDayOfWeek() first day of the first week} is the first + * day of the week year. + * + *

    The default implementation of this method throws an + * {@link UnsupportedOperationException}. + * + * @return the week year of this {@code Calendar} + * @exception UnsupportedOperationException + * if any week year numbering isn't supported + * in this {@code Calendar}. + * @see #isWeekDateSupported() + * @see #getFirstDayOfWeek() + * @see #getMinimalDaysInFirstWeek() + * @since 1.7 + */ + public int getWeekYear() { + throw new UnsupportedOperationException(); + } + + /** + * Sets the date of this {@code Calendar} with the the given date + * specifiers - week year, week of year, and day of week. + * + *

    Unlike the {@code set} method, all of the calendar fields + * and {@code time} values are calculated upon return. + * + *

    If {@code weekOfYear} is out of the valid week-of-year range + * in {@code weekYear}, the {@code weekYear} and {@code + * weekOfYear} values are adjusted in lenient mode, or an {@code + * IllegalArgumentException} is thrown in non-lenient mode. + * + *

    The default implementation of this method throws an + * {@code UnsupportedOperationException}. + * + * @param weekYear the week year + * @param weekOfYear the week number based on {@code weekYear} + * @param dayOfWeek the day of week value: one of the constants + * for the {@link #DAY_OF_WEEK} field: {@link + * #SUNDAY}, ..., {@link #SATURDAY}. + * @exception IllegalArgumentException + * if any of the given date specifiers is invalid + * or any of the calendar fields are inconsistent + * with the given date specifiers in non-lenient mode + * @exception UnsupportedOperationException + * if any week year numbering isn't supported in this + * {@code Calendar}. + * @see #isWeekDateSupported() + * @see #getFirstDayOfWeek() + * @see #getMinimalDaysInFirstWeek() + * @since 1.7 + */ + public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) { + throw new UnsupportedOperationException(); + } + + /** + * Returns the number of weeks in the week year represented by this + * {@code Calendar}. + * + *

    The default implementation of this method throws an + * {@code UnsupportedOperationException}. + * + * @return the number of weeks in the week year. + * @exception UnsupportedOperationException + * if any week year numbering isn't supported in this + * {@code Calendar}. + * @see #WEEK_OF_YEAR + * @see #isWeekDateSupported() + * @see #getWeekYear() + * @see #getActualMaximum(int) + * @since 1.7 + */ + public int getWeeksInWeekYear() { + throw new UnsupportedOperationException(); + } + /** * Returns the minimum value for the given calendar field of this * Calendar instance. The minimum value is defined as diff --git a/jdk/src/share/classes/java/util/ConcurrentModificationException.java b/jdk/src/share/classes/java/util/ConcurrentModificationException.java index b96b451aab9..956fbdfaf62 100644 --- a/jdk/src/share/classes/java/util/ConcurrentModificationException.java +++ b/jdk/src/share/classes/java/util/ConcurrentModificationException.java @@ -49,9 +49,9 @@ package java.util; *

    Note that fail-fast behavior cannot be guaranteed as it is, generally * speaking, impossible to make any hard guarantees in the presence of * unsynchronized concurrent modification. Fail-fast operations - * throw ConcurrentModificationException on a best-effort basis. + * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this - * exception for its correctness: ConcurrentModificationException + * exception for its correctness: {@code ConcurrentModificationException} * should be used only to detect bugs. * * @author Josh Bloch @@ -77,7 +77,7 @@ public class ConcurrentModificationException extends RuntimeException { } /** - * Constructs a ConcurrentModificationException with the + * Constructs a {@code ConcurrentModificationException} with the * specified detail message. * * @param message the detail message pertaining to this exception. @@ -85,4 +85,39 @@ public class ConcurrentModificationException extends RuntimeException { public ConcurrentModificationException(String message) { super(message); } + + /** + * Constructs a new exception with the specified cause and a detail + * message of {@code (cause==null ? null : cause.toString())} (which + * typically contains the class and detail message of {@code cause}. + * + * @param cause the cause (which is saved for later retrieval by the + * {@link Throwable#getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.7 + */ + public ConcurrentModificationException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new exception with the specified detail message and + * cause. + * + *

    Note that the detail message associated with cause is + * not automatically incorporated in this exception's detail + * message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link Throwable#getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link Throwable#getCause()} method). (A {@code null} value + * is permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.7 + */ + public ConcurrentModificationException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/jdk/src/share/classes/java/util/Currency.java b/jdk/src/share/classes/java/util/Currency.java index f7cedbe56cd..daae561219f 100644 --- a/jdk/src/share/classes/java/util/Currency.java +++ b/jdk/src/share/classes/java/util/Currency.java @@ -452,7 +452,7 @@ public final class Currency implements Serializable { * @return the symbol of this currency for the default locale */ public String getSymbol() { - return getSymbol(Locale.getDefault()); + return getSymbol(Locale.getDefault(Locale.Category.DISPLAY)); } /** @@ -528,7 +528,7 @@ public final class Currency implements Serializable { * @since 1.7 */ public String getDisplayName() { - return getDisplayName(Locale.getDefault()); + return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY)); } /** diff --git a/jdk/src/share/classes/java/util/Formatter.java b/jdk/src/share/classes/java/util/Formatter.java index 060ffd2768b..55fd610d39d 100644 --- a/jdk/src/share/classes/java/util/Formatter.java +++ b/jdk/src/share/classes/java/util/Formatter.java @@ -1866,7 +1866,7 @@ public final class Formatter implements Closeable, Flushable { * virtual machine. */ public Formatter() { - init(new StringBuilder(), Locale.getDefault()); + init(new StringBuilder(), Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -1882,7 +1882,7 @@ public final class Formatter implements Closeable, Flushable { public Formatter(Appendable a) { if (a == null) a = new StringBuilder(); - init(a, Locale.getDefault()); + init(a, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -1949,7 +1949,7 @@ public final class Formatter implements Closeable, Flushable { */ public Formatter(String fileName) throws FileNotFoundException { init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))), - Locale.getDefault()); + Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -1985,7 +1985,7 @@ public final class Formatter implements Closeable, Flushable { public Formatter(String fileName, String csn) throws FileNotFoundException, UnsupportedEncodingException { - this(fileName, csn, Locale.getDefault()); + this(fileName, csn, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -2057,7 +2057,7 @@ public final class Formatter implements Closeable, Flushable { */ public Formatter(File file) throws FileNotFoundException { init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))), - Locale.getDefault()); + Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -2093,7 +2093,7 @@ public final class Formatter implements Closeable, Flushable { public Formatter(File file, String csn) throws FileNotFoundException, UnsupportedEncodingException { - this(file, csn, Locale.getDefault()); + this(file, csn, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -2152,7 +2152,7 @@ public final class Formatter implements Closeable, Flushable { public Formatter(PrintStream ps) { if (ps == null) throw new NullPointerException(); - init((Appendable)ps, Locale.getDefault()); + init((Appendable)ps, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -2171,7 +2171,7 @@ public final class Formatter implements Closeable, Flushable { */ public Formatter(OutputStream os) { init(new BufferedWriter(new OutputStreamWriter(os)), - Locale.getDefault()); + Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -2195,7 +2195,7 @@ public final class Formatter implements Closeable, Flushable { public Formatter(OutputStream os, String csn) throws UnsupportedEncodingException { - this(os, csn, Locale.getDefault()); + this(os, csn, Locale.getDefault(Locale.Category.FORMAT)); } /** diff --git a/jdk/src/share/classes/java/util/GregorianCalendar.java b/jdk/src/share/classes/java/util/GregorianCalendar.java index 9c0ff0d5cd4..75402f0ff65 100644 --- a/jdk/src/share/classes/java/util/GregorianCalendar.java +++ b/jdk/src/share/classes/java/util/GregorianCalendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,23 +88,49 @@ import sun.util.calendar.ZoneInfo; * adjustment may be made if desired for dates that are prior to the Gregorian * changeover and which fall between January 1 and March 24. * - *

    Values calculated for the WEEK_OF_YEAR field range from 1 to - * 53. Week 1 for a year is the earliest seven day period starting on - * getFirstDayOfWeek() that contains at least - * getMinimalDaysInFirstWeek() days from that year. It thus - * depends on the values of getMinimalDaysInFirstWeek(), - * getFirstDayOfWeek(), and the day of the week of January 1. - * Weeks between week 1 of one year and week 1 of the following year are - * numbered sequentially from 2 to 52 or 53 (as needed). - - *

    For example, January 1, 1998 was a Thursday. If - * getFirstDayOfWeek() is MONDAY and - * getMinimalDaysInFirstWeek() is 4 (these are the values - * reflecting ISO 8601 and many national standards), then week 1 of 1998 starts - * on December 29, 1997, and ends on January 4, 1998. If, however, - * getFirstDayOfWeek() is SUNDAY, then week 1 of 1998 - * starts on January 4, 1998, and ends on January 10, 1998; the first three days - * of 1998 then are part of week 53 of 1997. + *

    Week Of Year and Week Year

    + * + *

    Values calculated for the {@link Calendar#WEEK_OF_YEAR + * WEEK_OF_YEAR} field range from 1 to 53. The first week of a + * calendar year is the earliest seven day period starting on {@link + * Calendar#getFirstDayOfWeek() getFirstDayOfWeek()} that contains at + * least {@link Calendar#getMinimalDaysInFirstWeek() + * getMinimalDaysInFirstWeek()} days from that year. It thus depends + * on the values of {@code getMinimalDaysInFirstWeek()}, {@code + * getFirstDayOfWeek()}, and the day of the week of January 1. Weeks + * between week 1 of one year and week 1 of the following year + * (exclusive) are numbered sequentially from 2 to 52 or 53 (except + * for year(s) involved in the Julian-Gregorian transition). + * + *

    The {@code getFirstDayOfWeek()} and {@code + * getMinimalDaysInFirstWeek()} values are initialized using + * locale-dependent resources when constructing a {@code + * GregorianCalendar}. The week + * determination is compatible with the ISO 8601 standard when {@code + * getFirstDayOfWeek()} is {@code MONDAY} and {@code + * getMinimalDaysInFirstWeek()} is 4, which values are used in locales + * where the standard is preferred. These values can explicitly be set by + * calling {@link Calendar#setFirstDayOfWeek(int) setFirstDayOfWeek()} and + * {@link Calendar#setMinimalDaysInFirstWeek(int) + * setMinimalDaysInFirstWeek()}. + * + *

    A week year is in sync with a + * {@code WEEK_OF_YEAR} cycle. All weeks between the first and last + * weeks (inclusive) have the same week year value. + * Therefore, the first and last days of a week year may have + * different calendar year values. + * + *

    For example, January 1, 1998 is a Thursday. If {@code + * getFirstDayOfWeek()} is {@code MONDAY} and {@code + * getMinimalDaysInFirstWeek()} is 4 (ISO 8601 standard compatible + * setting), then week 1 of 1998 starts on December 29, 1997, and ends + * on January 4, 1998. The week year is 1998 for the last three days + * of calendar year 1997. If, however, {@code getFirstDayOfWeek()} is + * {@code SUNDAY}, then week 1 of 1998 starts on January 4, 1998, and + * ends on January 10, 1998; the first three days of 1998 then are + * part of week 53 of 1997 and their week year is 1997. + * + *

    Week Of Month

    * *

    Values calculated for the WEEK_OF_MONTH field range from 0 * to 6. Week 1 of a month (the days with WEEK_OF_MONTH = @@ -124,7 +150,9 @@ import sun.util.calendar.ZoneInfo; * getMinimalDaysInFirstWeek() is changed to 3, then January 1 * through January 3 have a WEEK_OF_MONTH of 1. * - *

    The clear methods set calendar field(s) + *

    Default Fields Values

    + * + *

    The clear method sets calendar field(s) * undefined. GregorianCalendar uses the following * default value for each calendar field if its value is undefined. * @@ -555,7 +583,7 @@ public class GregorianCalendar extends Calendar { * in the default time zone with the default locale. */ public GregorianCalendar() { - this(TimeZone.getDefaultRef(), Locale.getDefault()); + this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT)); setZoneShared(true); } @@ -566,7 +594,7 @@ public class GregorianCalendar extends Calendar { * @param zone the given time zone. */ public GregorianCalendar(TimeZone zone) { - this(zone, Locale.getDefault()); + this(zone, Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -1625,6 +1653,13 @@ public class GregorianCalendar extends Calendar { * is 29 because 2004 is a leap year, and if the date of this * instance is February 1, 2005, it's 28. * + *

    This method calculates the maximum value of {@link + * Calendar#WEEK_OF_YEAR WEEK_OF_YEAR} based on the {@link + * Calendar#YEAR YEAR} (calendar year) value, not the week year. Call {@link + * #getWeeksInWeekYear()} to get the maximum value of {@code + * WEEK_OF_YEAR} in the week year of this {@code GregorianCalendar}. + * * @param field the calendar field * @return the maximum of the given field for the time value of * this GregorianCalendar @@ -1742,8 +1777,13 @@ public class GregorianCalendar extends Calendar { if (gc == this) { gc = (GregorianCalendar) gc.clone(); } - gc.set(DAY_OF_YEAR, getActualMaximum(DAY_OF_YEAR)); + int maxDayOfYear = getActualMaximum(DAY_OF_YEAR); + gc.set(DAY_OF_YEAR, maxDayOfYear); value = gc.get(WEEK_OF_YEAR); + if (internalGet(YEAR) != gc.getWeekYear()) { + gc.set(DAY_OF_YEAR, maxDayOfYear - 7); + value = gc.get(WEEK_OF_YEAR); + } } break; @@ -1934,46 +1974,241 @@ public class GregorianCalendar extends Calendar { } } -////////////////////// -// Proposed public API -////////////////////// + /** + * Returns {@code true} indicating this {@code GregorianCalendar} + * supports week dates. + * + * @return {@code true} (always) + * @see #getWeekYear() + * @see #setWeekDate(int,int,int) + * @see #getWeeksInWeekYear() + * @since 1.7 + */ + @Override + public final boolean isWeekDateSupported() { + return true; + } /** - * Returns the year that corresponds to the WEEK_OF_YEAR field. - * This may be one year before or after the Gregorian or Julian year stored - * in the YEAR field. For example, January 1, 1999 is considered - * Friday of week 53 of 1998 (if minimal days in first week is - * 2 or less, and the first day of the week is Sunday). Given - * these same settings, the ISO year of January 1, 1999 is - * 1998. + * Returns the week year represented by this + * {@code GregorianCalendar}. The dates in the weeks between 1 and the + * maximum week number of the week year have the same week year value + * that may be one year before or after the {@link Calendar#YEAR YEAR} + * (calendar year) value. * - *

    This method calls {@link Calendar#complete} before - * calculating the week-based year. + *

    This method calls {@link Calendar#complete()} before + * calculating the week year. * - * @return the year corresponding to the WEEK_OF_YEAR field, which - * may be one year before or after the YEAR field. - * @see #YEAR - * @see #WEEK_OF_YEAR + * @return the week year represented by this {@code GregorianCalendar}. + * If the {@link Calendar#ERA ERA} value is {@link #BC}, the year is + * represented by 0 or a negative number: BC 1 is 0, BC 2 + * is -1, BC 3 is -2, and so on. + * @throws IllegalArgumentException + * if any of the calendar fields is invalid in non-lenient mode. + * @see #isWeekDateSupported() + * @see #getWeeksInWeekYear() + * @see Calendar#getFirstDayOfWeek() + * @see Calendar#getMinimalDaysInFirstWeek() + * @since 1.7 */ - /* - public int getWeekBasedYear() { - complete(); - // TODO: Below doesn't work for gregorian cutover... - int weekOfYear = internalGet(WEEK_OF_YEAR); - int year = internalGet(YEAR); - if (internalGet(MONTH) == Calendar.JANUARY) { - if (weekOfYear >= 52) { + @Override + public int getWeekYear() { + int year = get(YEAR); // implicitly calls complete() + if (internalGetEra() == BCE) { + year = 1 - year; + } + + // Fast path for the Gregorian calendar years that are never + // affected by the Julian-Gregorian transition + if (year > gregorianCutoverYear + 1) { + int weekOfYear = internalGet(WEEK_OF_YEAR); + if (internalGet(MONTH) == JANUARY) { + if (weekOfYear >= 52) { + --year; + } + } else { + if (weekOfYear == 1) { + ++year; + } + } + return year; + } + + // General (slow) path + int dayOfYear = internalGet(DAY_OF_YEAR); + int maxDayOfYear = getActualMaximum(DAY_OF_YEAR); + int minimalDays = getMinimalDaysInFirstWeek(); + + // Quickly check the possibility of year adjustments before + // cloning this GregorianCalendar. + if (dayOfYear > minimalDays && dayOfYear < (maxDayOfYear - 6)) { + return year; + } + + // Create a clone to work on the calculation + GregorianCalendar cal = (GregorianCalendar) clone(); + cal.setLenient(true); + // Use GMT so that intermediate date calculations won't + // affect the time of day fields. + cal.setTimeZone(TimeZone.getTimeZone("GMT")); + // Go to the first day of the year, which is usually January 1. + cal.set(DAY_OF_YEAR, 1); + cal.complete(); + + // Get the first day of the first day-of-week in the year. + int delta = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK); + if (delta != 0) { + if (delta < 0) { + delta += 7; + } + cal.add(DAY_OF_YEAR, delta); + } + int minDayOfYear = cal.get(DAY_OF_YEAR); + if (dayOfYear < minDayOfYear) { + if (minDayOfYear <= minimalDays) { --year; } } else { - if (weekOfYear == 1) { - ++year; + cal.set(YEAR, year + 1); + cal.set(DAY_OF_YEAR, 1); + cal.complete(); + int del = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK); + if (del != 0) { + if (del < 0) { + del += 7; + } + cal.add(DAY_OF_YEAR, del); + } + minDayOfYear = cal.get(DAY_OF_YEAR) - 1; + if (minDayOfYear == 0) { + minDayOfYear = 7; + } + if (minDayOfYear >= minimalDays) { + int days = maxDayOfYear - dayOfYear + 1; + if (days <= (7 - minDayOfYear)) { + ++year; + } } } return year; } - */ + /** + * Sets this {@code GregorianCalendar} to the date given by the + * date specifiers - {@code weekYear}, + * {@code weekOfYear}, and {@code dayOfWeek}. {@code weekOfYear} + * follows the {@code WEEK_OF_YEAR} + * numbering. The {@code dayOfWeek} value must be one of the + * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} values: {@link + * Calendar#SUNDAY SUNDAY} to {@link Calendar#SATURDAY SATURDAY}. + * + *

    Note that the numeric day-of-week representation differs from + * the ISO 8601 standard, and that the {@code weekOfYear} + * numbering is compatible with the standard when {@code + * getFirstDayOfWeek()} is {@code MONDAY} and {@code + * getMinimalDaysInFirstWeek()} is 4. + * + *

    Unlike the {@code set} method, all of the calendar fields + * and the instant of time value are calculated upon return. + * + *

    If {@code weekOfYear} is out of the valid week-of-year + * range in {@code weekYear}, the {@code weekYear} + * and {@code weekOfYear} values are adjusted in lenient + * mode, or an {@code IllegalArgumentException} is thrown in + * non-lenient mode. + * + * @param weekYear the week year + * @param weekOfYear the week number based on {@code weekYear} + * @param dayOfWeek the day of week value: one of the constants + * for the {@link #DAY_OF_WEEK DAY_OF_WEEK} field: + * {@link Calendar#SUNDAY SUNDAY}, ..., + * {@link Calendar#SATURDAY SATURDAY}. + * @exception IllegalArgumentException + * if any of the given date specifiers is invalid, + * or if any of the calendar fields are inconsistent + * with the given date specifiers in non-lenient mode + * @see GregorianCalendar#isWeekDateSupported() + * @see Calendar#getFirstDayOfWeek() + * @see Calendar#getMinimalDaysInFirstWeek() + * @since 1.7 + */ + @Override + public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) { + if (dayOfWeek < SUNDAY || dayOfWeek > SATURDAY) { + throw new IllegalArgumentException("invalid dayOfWeek: " + dayOfWeek); + } + + // To avoid changing the time of day fields by date + // calculations, use a clone with the GMT time zone. + GregorianCalendar gc = (GregorianCalendar) clone(); + gc.setLenient(true); + int era = gc.get(ERA); + gc.clear(); + gc.setTimeZone(TimeZone.getTimeZone("GMT")); + gc.set(ERA, era); + gc.set(YEAR, weekYear); + gc.set(WEEK_OF_YEAR, 1); + gc.set(DAY_OF_WEEK, getFirstDayOfWeek()); + int days = dayOfWeek - getFirstDayOfWeek(); + if (days < 0) { + days += 7; + } + days += 7 * (weekOfYear - 1); + if (days != 0) { + gc.add(DAY_OF_YEAR, days); + } else { + gc.complete(); + } + + if (!isLenient() && + (gc.getWeekYear() != weekYear + || gc.internalGet(WEEK_OF_YEAR) != weekOfYear + || gc.internalGet(DAY_OF_WEEK) != dayOfWeek)) { + throw new IllegalArgumentException(); + } + + set(ERA, gc.internalGet(ERA)); + set(YEAR, gc.internalGet(YEAR)); + set(MONTH, gc.internalGet(MONTH)); + set(DAY_OF_MONTH, gc.internalGet(DAY_OF_MONTH)); + + // to avoid throwing an IllegalArgumentException in + // non-lenient, set WEEK_OF_YEAR internally + internalSet(WEEK_OF_YEAR, weekOfYear); + complete(); + } + + /** + * Returns the number of weeks in the week year + * represented by this {@code GregorianCalendar}. + * + *

    For example, if this {@code GregorianCalendar}'s date is + * December 31, 2008 with the ISO + * 8601 compatible setting, this method will return 53 for the + * period: December 29, 2008 to January 3, 2010 while {@link + * #getActualMaximum(int) getActualMaximum(WEEK_OF_YEAR)} will return + * 52 for the period: December 31, 2007 to December 28, 2008. + * + * @return the number of weeks in the week year. + * @see Calendar#WEEK_OF_YEAR + * @see #getWeekYear() + * @see #getActualMaximum(int) + * @since 1.7 + */ + public int getWeeksInWeekYear() { + GregorianCalendar gc = getNormalizedCalendar(); + int weekYear = gc.getWeekYear(); + if (weekYear == gc.internalGet(YEAR)) { + return gc.getActualMaximum(WEEK_OF_YEAR); + } + + // Use the 2nd week for calculating the max of WEEK_OF_YEAR + if (gc == this) { + gc = (GregorianCalendar) gc.clone(); + } + gc.setWeekDate(weekYear, 2, internalGet(DAY_OF_WEEK)); + return gc.getActualMaximum(WEEK_OF_YEAR); + } ///////////////////////////// // Time => Fields computation @@ -2178,7 +2413,7 @@ public class GregorianCalendar extends Calendar { // If we are in the cutover year, we need some special handling. if (normalizedYear == cutoverYear) { // Need to take care of the "missing" days. - if (getCutoverCalendarSystem() == jcal) { + if (gregorianCutoverYearJulian <= gregorianCutoverYear) { // We need to find out where we are. The cutover // gap could even be more than one year. (One // year difference in ~48667 years.) @@ -2208,27 +2443,36 @@ public class GregorianCalendar extends Calendar { // December 31, which is not always true in // GregorianCalendar. long fixedDec31 = fixedDateJan1 - 1; - long prevJan1; + long prevJan1 = fixedDateJan1 - 365; if (normalizedYear > (cutoverYear + 1)) { - prevJan1 = fixedDateJan1 - 365; if (CalendarUtils.isGregorianLeapYear(normalizedYear - 1)) { --prevJan1; } + } else if (normalizedYear <= gregorianCutoverYearJulian) { + if (CalendarUtils.isJulianLeapYear(normalizedYear - 1)) { + --prevJan1; + } } else { BaseCalendar calForJan1 = calsys; - int prevYear = normalizedYear - 1; - if (prevYear == cutoverYear) { + //int prevYear = normalizedYear - 1; + int prevYear = getCalendarDate(fixedDec31).getNormalizedYear(); + if (prevYear == gregorianCutoverYear) { calForJan1 = getCutoverCalendarSystem(); - } - prevJan1 = calForJan1.getFixedDate(prevYear, - BaseCalendar.JANUARY, - 1, - null); - while (prevJan1 > fixedDec31) { - prevJan1 = getJulianCalendarSystem().getFixedDate(--prevYear, - BaseCalendar.JANUARY, - 1, - null); + if (calForJan1 == jcal) { + prevJan1 = calForJan1.getFixedDate(prevYear, + BaseCalendar.JANUARY, + 1, + null); + } else { + prevJan1 = gregorianCutoverDate; + calForJan1 = gcal; + } + } else if (prevYear <= gregorianCutoverYearJulian) { + calForJan1 = getJulianCalendarSystem(); + prevJan1 = calForJan1.getFixedDate(prevYear, + BaseCalendar.JANUARY, + 1, + null); } } weekOfYear = getWeekNumber(prevJan1, fixedDec31); @@ -2260,14 +2504,20 @@ public class GregorianCalendar extends Calendar { if (nextYear == gregorianCutoverYear) { calForJan1 = getCutoverCalendarSystem(); } - long nextJan1 = calForJan1.getFixedDate(nextYear, - BaseCalendar.JANUARY, - 1, - null); - if (nextJan1 < fixedDate) { + + long nextJan1; + if (nextYear > gregorianCutoverYear + || gregorianCutoverYearJulian == gregorianCutoverYear + || nextYear == gregorianCutoverYearJulian) { + nextJan1 = calForJan1.getFixedDate(nextYear, + BaseCalendar.JANUARY, + 1, + null); + } else { nextJan1 = gregorianCutoverDate; calForJan1 = gcal; } + long nextJan1st = calForJan1.getDayOfWeekDateOnOrBefore(nextJan1 + 6, getFirstDayOfWeek()); int ndays = (int)(nextJan1st - nextJan1); @@ -2409,10 +2659,24 @@ public class GregorianCalendar extends Calendar { } gfd = jfd; } else { - gfd = fixedDate + getFixedDate(gcal, year, fieldMask); jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask); + gfd = fixedDate + getFixedDate(gcal, year, fieldMask); } + // Now we have to determine which calendar date it is. + + // If the date is relative from the beginning of the year + // in the Julian calendar, then use jfd; + if (isFieldSet(fieldMask, DAY_OF_YEAR) || isFieldSet(fieldMask, WEEK_OF_YEAR)) { + if (gregorianCutoverYear == gregorianCutoverYearJulian) { + fixedDate = jfd; + break calculateFixedDate; + } else if (year == gregorianCutoverYear) { + fixedDate = gfd; + break calculateFixedDate; + } + } + if (gfd >= gregorianCutoverDate) { if (jfd >= gregorianCutoverDate) { fixedDate = gfd; @@ -2494,9 +2758,10 @@ public class GregorianCalendar extends Calendar { continue; } if (originalFields[field] != internalGet(field)) { + String s = originalFields[field] + " -> " + internalGet(field); // Restore the original field values System.arraycopy(originalFields, 0, fields, 0, fields.length); - throw new IllegalArgumentException(getFieldName(field)); + throw new IllegalArgumentException(getFieldName(field) + ": " + s); } } } @@ -2669,9 +2934,7 @@ public class GregorianCalendar extends Calendar { * method returns Gregorian. Otherwise, Julian. */ private BaseCalendar getCutoverCalendarSystem() { - CalendarDate date = getGregorianCutoverDate(); - if (date.getMonth() == BaseCalendar.JANUARY - && date.getDayOfMonth() == 1) { + if (gregorianCutoverYearJulian < gregorianCutoverYear) { return gcal; } return getJulianCalendarSystem(); diff --git a/jdk/src/share/classes/java/util/IllformedLocaleException.java b/jdk/src/share/classes/java/util/IllformedLocaleException.java new file mode 100644 index 00000000000..5c0c4da1314 --- /dev/null +++ b/jdk/src/share/classes/java/util/IllformedLocaleException.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2010, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ + +package java.util; + +/** + * Thrown by methods in {@link Locale} and {@link Locale.Builder} to + * indicate that an argument is not a well-formed BCP 47 tag. + * + * @see Locale + * @since 1.7 + */ +public class IllformedLocaleException extends RuntimeException { + + private static final long serialVersionUID = -5245986824925681401L; + + private int _errIdx = -1; + + /** + * Constructs a new IllformedLocaleException with no + * detail message and -1 as the error index. + */ + public IllformedLocaleException() { + super(); + } + + /** + * Constructs a new IllformedLocaleException with the + * given message and -1 as the error index. + * + * @param message the message + */ + public IllformedLocaleException(String message) { + super(message); + } + + /** + * Constructs a new IllformedLocaleException with the + * given message and the error index. The error index is the approximate + * offset from the start of the ill-formed value to the point where the + * parse first detected an error. A negative error index value indicates + * either the error index is not applicable or unknown. + * + * @param message the message + * @param errorIndex the index + */ + public IllformedLocaleException(String message, int errorIndex) { + super(message + ((errorIndex < 0) ? "" : " [at index " + errorIndex + "]")); + _errIdx = errorIndex; + } + + /** + * Returns the index where the error was found. A negative value indicates + * either the error index is not applicable or unknown. + * + * @return the error index + */ + public int getErrorIndex() { + return _errIdx; + } +} diff --git a/jdk/src/share/classes/java/util/Locale.java b/jdk/src/share/classes/java/util/Locale.java index c3137f6dd16..49b85866ed3 100644 --- a/jdk/src/share/classes/java/util/Locale.java +++ b/jdk/src/share/classes/java/util/Locale.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,86 +40,240 @@ package java.util; -import java.io.*; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; +import java.io.Serializable; import java.security.AccessController; import java.text.MessageFormat; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; import java.util.spi.LocaleNameProvider; -import java.util.spi.LocaleServiceProvider; + import sun.security.action.GetPropertyAction; import sun.util.LocaleServiceProviderPool; +import sun.util.locale.AsciiUtil; +import sun.util.locale.BaseLocale; +import sun.util.locale.InternalLocaleBuilder; +import sun.util.locale.LanguageTag; +import sun.util.locale.LocaleExtensions; +import sun.util.locale.LocaleObjectCache; +import sun.util.locale.LocaleSyntaxException; +import sun.util.locale.ParseStatus; +import sun.util.locale.UnicodeLocaleExtension; import sun.util.resources.LocaleData; import sun.util.resources.OpenListResourceBundle; /** - * * A Locale object represents a specific geographical, political, * or cultural region. An operation that requires a Locale to perform * its task is called locale-sensitive and uses the Locale * to tailor information for the user. For example, displaying a number - * is a locale-sensitive operation--the number should be formatted - * according to the customs/conventions of the user's native country, + * is a locale-sensitive operation— the number should be formatted + * according to the customs and conventions of the user's native country, * region, or culture. * - *

    - * Create a Locale object using the constructors in this class: + *

    The Locale class implements identifiers + * interchangeable with BCP 47 (IETF BCP 47, "Tags for Identifying + * Languages"), with support for the LDML (UTS#35, "Unicode Locale + * Data Markup Language") BCP 47-compatible extensions for locale data + * exchange. + * + *

    A Locale object logically consists of the fields + * described below. + * + *

    + *
    language
    + * + *
    ISO 639 alpha-2 or alpha-3 language code, or registered + * language subtags up to 8 alpha letters (for future enhancements). + * When a language has both an alpha-2 code and an alpha-3 code, the + * alpha-2 code must be used. You can find a full list of valid + * language codes in the IANA Language Subtag Registry (search for + * "Type: language"). The language field is case insensitive, but + * Locale always canonicalizes to lower case.

    + * + *
    Well-formed language values have the form + * [a-zA-Z]{2,8}. Note that this is not the the full + * BCP47 language production, since it excludes extlang. They are + * not needed since modern three-letter language codes replace + * them.

    + * + *
    Example: "en" (English), "ja" (Japanese), "kok" (Konkani)

    + * + *
    script
    + * + *
    ISO 15924 alpha-4 script code. You can find a full list of + * valid script codes in the IANA Language Subtag Registry (search + * for "Type: script"). The script field is case insensitive, but + * Locale always canonicalizes to title case (the first + * letter is upper case and the rest of the letters are lower + * case).

    + * + *
    Well-formed script values have the form + * [a-zA-Z]{4}

    + * + *
    Example: "Latn" (Latin), "Cyrl" (Cyrillic)

    + * + *
    country (region)
    + * + *
    ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code. + * You can find a full list of valid country and region codes in the + * IANA Language Subtag Registry (search for "Type: region"). The + * country (region) field is case insensitive, but + * Locale always canonicalizes to upper case.

    + * + *
    Well-formed country/region values have + * the form [a-zA-Z]{2} | [0-9]{3}

    + * + *
    Example: "US" (United States), "FR" (France), "029" + * (Caribbean)

    + * + *
    variant
    + * + *
    Any arbitrary value used to indicate a variation of a + * Locale. Where there are two or more variant values + * each indicating its own semantics, these values should be ordered + * by importance, with most important first, separated by + * underscore('_'). The variant field is case sensitive.

    + * + *
    Note: IETF BCP 47 places syntactic restrictions on variant + * subtags. Also BCP 47 subtags are strictly used to indicate + * additional variations that define a language or its dialects that + * are not covered by any combinations of language, script and + * region subtags. You can find a full list of valid variant codes + * in the IANA Language Subtag Registry (search for "Type: variant"). + * + *

    However, the variant field in Locale has + * historically been used for any kind of variation, not just + * language variations. For example, some supported variants + * available in Java SE Runtime Environments indicate alternative + * cultural behaviors such as calendar type or number script. In + * BCP 47 this kind of information, which does not identify the + * language, is supported by extension subtags or private use + * subtags.


    + * + *
    Well-formed variant values have the form SUBTAG + * (('_'|'-') SUBTAG)* where SUBTAG = + * [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}. (Note: BCP 47 only + * uses hyphen ('-') as a delimiter, this is more lenient).

    + * + *
    Example: "polyton" (Polytonic Greek), "POSIX"

    + * + *
    extensions
    + * + *
    A map from single character keys to string values, indicating + * extensions apart from language identification. The extensions in + * Locale implement the semantics and syntax of BCP 47 + * extension subtags and private use subtags. The extensions are + * case insensitive, but Locale canonicalizes all + * extension keys and values to lower case. Note that extensions + * cannot have empty values.

    + * + *
    Well-formed keys are single characters from the set + * [0-9a-zA-Z]. Well-formed values have the form + * SUBTAG ('-' SUBTAG)* where for the key 'x' + * SUBTAG = [0-9a-zA-Z]{1,8} and for other keys + * SUBTAG = [0-9a-zA-Z]{2,8} (that is, 'x' allows + * single-character subtags).

    + * + *
    Example: key="u"/value="ca-japanese" (Japanese Calendar), + * key="x"/value="java-1-7"
    + *
    + * + * Note: Although BCP 47 requires field values to be registered + * in the IANA Language Subtag Registry, the Locale class + * does not provide any validation features. The Builder + * only checks if an individual field satisfies the syntactic + * requirement (is well-formed), but does not validate the value + * itself. See {@link Builder} for details. + * + *

    Unicode locale/language extension

    + * + *

    UTS#35, "Unicode Locale Data Markup Language" defines optional + * attributes and keywords to override or refine the default behavior + * associated with a locale. A keyword is represented by a pair of + * key and type. For example, "nu-thai" indicates that Thai local + * digits (value:"thai") should be used for formatting numbers + * (key:"nu"). + * + *

    The keywords are mapped to a BCP 47 extension value using the + * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}). The above + * example, "nu-thai", becomes the extension "u-nu-thai".code + * + *

    Thus, when a Locale object contains Unicode locale + * attributes and keywords, + * getExtension(UNICODE_LOCALE_EXTENSION) will return a + * String representing this information, for example, "nu-thai". The + * Locale class also provides {@link + * #getUnicodeLocaleAttributes}, {@link #getUnicodeLocaleKeys}, and + * {@link #getUnicodeLocaleType} which allow you to access Unicode + * locale attributes and key/type pairs directly. When represented as + * a string, the Unicode Locale Extension lists attributes + * alphabetically, followed by key/type sequences with keys listed + * alphabetically (the order of subtags comprising a key's type is + * fixed when the type is defined) + * + *

    A well-formed locale key has the form + * [0-9a-zA-Z]{2}. A well-formed locale type has the + * form "" | [0-9a-zA-Z]{3,8} ('-' [0-9a-zA-Z]{3,8})* (it + * can be empty, or a series of subtags 3-8 alphanums in length). A + * well-formed locale attribute has the form + * [0-9a-zA-Z]{3,8} (it is a single subtag with the same + * form as a locale type subtag). + * + *

    The Unicode locale extension specifies optional behavior in + * locale-sensitive services. Although the LDML specification defines + * various keys and values, actual locale-sensitive service + * implementations in a Java Runtime Environment might not support any + * particular Unicode locale attributes or key/type pairs. + * + *

    Creating a Locale

    + * + *

    There are several different ways to create a Locale + * object. + * + *

    Builder
    + * + *

    Using {@link Builder} you can construct a Locale object + * that conforms to BCP 47 syntax. + * + *

    Constructors
    + * + *

    The Locale class provides three constructors: *

    *
    - * Locale(String language)
    - * Locale(String language, String country)
    - * Locale(String language, String country, String variant)
    + *     {@link #Locale(String language)}
    + *     {@link #Locale(String language, String country)}
    + *     {@link #Locale(String language, String country, String variant)}
      * 
    *
    - * The language argument is a valid ISO Language Code. - * These codes are the lower-case, two-letter codes as defined by ISO-639. - * You can find a full list of these codes at a number of sites, such as: - *
    - * http://www.loc.gov/standards/iso639-2/php/English_list.php + * These constructors allow you to create a Locale object + * with language, country and variant, but you cannot specify + * script or extensions. * - *

    - * The country argument is a valid ISO Country Code. These - * codes are the upper-case, two-letter codes as defined by ISO-3166. - * You can find a full list of these codes at a number of sites, such as: - *
    - * http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html + *

    Factory Methods
    * - *

    - * The variant argument is a vendor or browser-specific code. - * For example, use WIN for Windows, MAC for Macintosh, and POSIX for POSIX. - * Where there are two variants, separate them with an underscore, and - * put the most important one first. For example, a Traditional Spanish collation - * might construct a locale with parameters for language, country and variant as: - * "es", "ES", "Traditional_WIN". + *

    The method {@link #forLanguageTag} creates a Locale + * object for a well-formed BCP 47 language tag. * - *

    - * Because a Locale object is just an identifier for a region, - * no validity check is performed when you construct a Locale. - * If you want to see whether particular resources are available for the - * Locale you construct, you must query those resources. For - * example, ask the NumberFormat for the locales it supports - * using its getAvailableLocales method. - *
    Note: When you ask for a resource for a particular - * locale, you get back the best available match, not necessarily - * precisely what you asked for. For more information, look at - * {@link ResourceBundle}. + *

    Locale Constants
    * - *

    - * The Locale class provides a number of convenient constants + *

    The Locale class provides a number of convenient constants * that you can use to create Locale objects for commonly used * locales. For example, the following creates a Locale object * for the United States: *

    *
    - * Locale.US
    + *     Locale.US
      * 
    *
    * - *

    - * Once you've created a Locale you can query it for information about - * itself. Use getCountry to get the ISO Country Code and - * getLanguage to get the ISO Language Code. You can - * use getDisplayCountry to get the + *

    Use of Locale

    + * + *

    Once you've created a Locale you can query it for information + * about itself. Use getCountry to get the country (or region) + * code and getLanguage to get the language code. + * You can use getDisplayCountry to get the * name of the country suitable for displaying to the user. Similarly, * you can use getDisplayLanguage to get the name of * the language suitable for displaying to the user. Interestingly, @@ -127,28 +281,27 @@ import sun.util.resources.OpenListResourceBundle; * and have two versions: one that uses the default locale and one * that uses the locale specified as an argument. * - *

    - * The Java Platform provides a number of classes that perform locale-sensitive + *

    The Java Platform provides a number of classes that perform locale-sensitive * operations. For example, the NumberFormat class formats - * numbers, currency, or percentages in a locale-sensitive manner. Classes - * such as NumberFormat have a number of convenience methods + * numbers, currency, and percentages in a locale-sensitive manner. Classes + * such as NumberFormat have several convenience methods * for creating a default object of that type. For example, the * NumberFormat class provides these three convenience methods * for creating a default NumberFormat object: *

    *
    - * NumberFormat.getInstance()
    - * NumberFormat.getCurrencyInstance()
    - * NumberFormat.getPercentInstance()
    + *     NumberFormat.getInstance()
    + *     NumberFormat.getCurrencyInstance()
    + *     NumberFormat.getPercentInstance()
      * 
    *
    - * These methods have two variants; one with an explicit locale - * and one without; the latter using the default locale. + * Each of these methods has two variants; one with an explicit locale + * and one without; the latter uses the default locale: *
    *
    - * NumberFormat.getInstance(myLocale)
    - * NumberFormat.getCurrencyInstance(myLocale)
    - * NumberFormat.getPercentInstance(myLocale)
    + *     NumberFormat.getInstance(myLocale)
    + *     NumberFormat.getCurrencyInstance(myLocale)
    + *     NumberFormat.getPercentInstance(myLocale)
      * 
    *
    * A Locale is the mechanism for identifying the kind of object @@ -156,75 +309,162 @@ import sun.util.resources.OpenListResourceBundle; * just a mechanism for identifying objects, * not a container for the objects themselves. * - * @see ResourceBundle - * @see java.text.Format - * @see java.text.NumberFormat - * @see java.text.Collator - * @author Mark Davis - * @since 1.1 + *

    Compatibility

    + * + *

    In order to maintain compatibility with existing usage, Locale's + * constructors retain their behavior prior to the Java Runtime + * Environment version 1.7. The same is largely true for the + * toString method. Thus Locale objects can continue to + * be used as they were. In particular, clients who parse the output + * of toString into language, country, and variant fields can continue + * to do so (although this is strongly discouraged), although the + * variant field will have additional information in it if script or + * extensions are present. + * + *

    In addition, BCP 47 imposes syntax restrictions that are not + * imposed by Locale's constructors. This means that conversions + * between some Locales and BCP 47 language tags cannot be made without + * losing information. Thus toLanguageTag cannot + * represent the state of locales whose language, country, or variant + * do not conform to BCP 47. + * + *

    Because of these issues, it is recommended that clients migrate + * away from constructing non-conforming locales and use the + * forLanguageTag and Locale.Builder APIs instead. + * Clients desiring a string representation of the complete locale can + * then always rely on toLanguageTag for this purpose. + * + *

    Special cases
    + * + *

    For compatibility reasons, two + * non-conforming locales are treated as special cases. These are + * ja_JP_JP and th_TH_TH. These are ill-formed + * in BCP 47 since the variants are too short. To ease migration to BCP 47, + * these are treated specially during construction. These two cases (and only + * these) cause a constructor to generate an extension, all other values behave + * exactly as they did prior to Java 7. + * + *

    Java has used ja_JP_JP to represent Japanese as used in + * Japan together with the Japanese Imperial calendar. This is now + * representable using a Unicode locale extension, by specifying the + * Unicode locale key ca (for "calendar") and type + * japanese. When the Locale constructor is called with the + * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is + * automatically added. + * + *

    Java has used th_TH_TH to represent Thai as used in + * Thailand together with Thai digits. This is also now representable using + * a Unicode locale extension, by specifying the Unicode locale key + * nu (for "number") and value thai. When the Locale + * constructor is called with the arguments "th", "TH", "TH", the + * extension "u-nu-thai" is automatically added. + * + *

    Serialization
    + * + *

    During serialization, writeObject writes all fields to the output + * stream, including extensions. + * + *

    During deserialization, readResolve adds extensions as described + * in Special Cases, only + * for the two cases th_TH_TH and ja_JP_JP. + * + *

    Legacy language codes
    + * + *

    Locale's constructor has always converted three language codes to + * their earlier, obsoleted forms: he maps to iw, + * yi maps to ji, and id maps to + * in. This continues to be the case, in order to not break + * backwards compatibility. + * + *

    The APIs added in 1.7 map between the old and new language codes, + * maintaining the old codes internal to Locale (so that + * getLanguage and toString reflect the old + * code), but using the new codes in the BCP 47 language tag APIs (so + * that toLanguageTag reflects the new one). This + * preserves the equivalence between Locales no matter which code or + * API is used to construct them. Java's default resource bundle + * lookup mechanism also implements this mapping, so that resources + * can be named using either convention, see {@link ResourceBundle.Control}. + * + *

    Three-letter language/country(region) codes
    + * + *

    The Locale constructors have always specified that the language + * and the country param be two characters in length, although in + * practice they have accepted any length. The specification has now + * been relaxed to allow language codes of two to eight characters and + * country (region) codes of two to three characters, and in + * particular, three-letter language codes and three-digit region + * codes as specified in the IANA Language Subtag Registry. For + * compatibility, the implementation still does not impose a length + * constraint. + * + * @see Builder + * @see ResourceBundle + * @see java.text.Format + * @see java.text.NumberFormat + * @see java.text.Collator + * @author Mark Davis + * @since 1.1 */ - public final class Locale implements Cloneable, Serializable { - // cache to store singleton Locales - private final static ConcurrentHashMap cache = - new ConcurrentHashMap(32); + static private final Cache LOCALECACHE = new Cache(); /** Useful constant for language. */ - static public final Locale ENGLISH = createSingleton("en__", "en", ""); + static public final Locale ENGLISH = getInstance("en", "", ""); /** Useful constant for language. */ - static public final Locale FRENCH = createSingleton("fr__", "fr", ""); + static public final Locale FRENCH = getInstance("fr", "", ""); /** Useful constant for language. */ - static public final Locale GERMAN = createSingleton("de__", "de", ""); + static public final Locale GERMAN = getInstance("de", "", ""); /** Useful constant for language. */ - static public final Locale ITALIAN = createSingleton("it__", "it", ""); + static public final Locale ITALIAN = getInstance("it", "", ""); /** Useful constant for language. */ - static public final Locale JAPANESE = createSingleton("ja__", "ja", ""); + static public final Locale JAPANESE = getInstance("ja", "", ""); /** Useful constant for language. */ - static public final Locale KOREAN = createSingleton("ko__", "ko", ""); + static public final Locale KOREAN = getInstance("ko", "", ""); /** Useful constant for language. */ - static public final Locale CHINESE = createSingleton("zh__", "zh", ""); + static public final Locale CHINESE = getInstance("zh", "", ""); /** Useful constant for language. */ - static public final Locale SIMPLIFIED_CHINESE = createSingleton("zh_CN_", "zh", "CN"); + static public final Locale SIMPLIFIED_CHINESE = getInstance("zh", "CN", ""); /** Useful constant for language. */ - static public final Locale TRADITIONAL_CHINESE = createSingleton("zh_TW_", "zh", "TW"); + static public final Locale TRADITIONAL_CHINESE = getInstance("zh", "TW", ""); /** Useful constant for country. */ - static public final Locale FRANCE = createSingleton("fr_FR_", "fr", "FR"); + static public final Locale FRANCE = getInstance("fr", "FR", ""); /** Useful constant for country. */ - static public final Locale GERMANY = createSingleton("de_DE_", "de", "DE"); + static public final Locale GERMANY = getInstance("de", "DE", ""); /** Useful constant for country. */ - static public final Locale ITALY = createSingleton("it_IT_", "it", "IT"); + static public final Locale ITALY = getInstance("it", "IT", ""); /** Useful constant for country. */ - static public final Locale JAPAN = createSingleton("ja_JP_", "ja", "JP"); + static public final Locale JAPAN = getInstance("ja", "JP", ""); /** Useful constant for country. */ - static public final Locale KOREA = createSingleton("ko_KR_", "ko", "KR"); + static public final Locale KOREA = getInstance("ko", "KR", ""); /** Useful constant for country. */ @@ -240,19 +480,19 @@ public final class Locale implements Cloneable, Serializable { /** Useful constant for country. */ - static public final Locale UK = createSingleton("en_GB_", "en", "GB"); + static public final Locale UK = getInstance("en", "GB", ""); /** Useful constant for country. */ - static public final Locale US = createSingleton("en_US_", "en", "US"); + static public final Locale US = getInstance("en", "US", ""); /** Useful constant for country. */ - static public final Locale CANADA = createSingleton("en_CA_", "en", "CA"); + static public final Locale CANADA = getInstance("en", "CA", ""); /** Useful constant for country. */ - static public final Locale CANADA_FRENCH = createSingleton("fr_CA_", "fr", "CA"); + static public final Locale CANADA_FRENCH = getInstance("fr", "CA", ""); /** * Useful constant for the root locale. The root locale is the locale whose @@ -262,7 +502,25 @@ public final class Locale implements Cloneable, Serializable { * * @since 1.6 */ - static public final Locale ROOT = createSingleton("__", "", ""); + static public final Locale ROOT = getInstance("", "", ""); + + /** + * The key for the private use extension ('x'). + * + * @see #getExtension(char) + * @see Builder#setExtension(char, String) + * @since 1.7 + */ + static public final char PRIVATE_USE_EXTENSION = 'x'; + + /** + * The key for Unicode locale extension ('u'). + * + * @see #getExtension(char) + * @see Builder#setExtension(char, String) + * @since 1.7 + */ + static public final char UNICODE_LOCALE_EXTENSION = 'u'; /** serialization ID */ @@ -274,32 +532,67 @@ public final class Locale implements Cloneable, Serializable { private static final int DISPLAY_LANGUAGE = 0; private static final int DISPLAY_COUNTRY = 1; private static final int DISPLAY_VARIANT = 2; + private static final int DISPLAY_SCRIPT = 3; /** - * Construct a locale from language, country, variant. - * NOTE: ISO 639 is not a stable standard; some of the language codes it defines - * (specifically iw, ji, and in) have changed. This constructor accepts both the - * old codes (iw, ji, and in) and the new codes (he, yi, and id), but all other - * API on Locale will return only the OLD codes. - * @param language lowercase two-letter ISO-639 code. - * @param country uppercase two-letter ISO-3166 code. - * @param variant vendor and browser specific code. See class description. - * @exception NullPointerException thrown if any argument is null. + * Private constructor used by getInstance method */ - public Locale(String language, String country, String variant) { - this.language = convertOldISOCodes(language); - this.country = toUpperCase(country).intern(); - this.variant = variant.intern(); + private Locale(BaseLocale baseLocale, LocaleExtensions extensions) { + _baseLocale = baseLocale; + _extensions = extensions; } /** - * Construct a locale from language, country. - * NOTE: ISO 639 is not a stable standard; some of the language codes it defines - * (specifically iw, ji, and in) have changed. This constructor accepts both the - * old codes (iw, ji, and in) and the new codes (he, yi, and id), but all other + * Construct a locale from language, country and variant. + * This constructor normalizes the language value to lowercase and + * the country value to uppercase. + *

    + * Note: + *

      + *
    • ISO 639 is not a stable standard; some of the language codes it defines + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other * API on Locale will return only the OLD codes. - * @param language lowercase two-letter ISO-639 code. - * @param country uppercase two-letter ISO-3166 code. + *
    • For backward compatibility reasons, this constructor does not make + * any syntactic checks on the input. + *
    • The two cases ("ja", "JP", "JP") and ("th", "TH", "TH") are handled specially, + * see Special Cases for more information. + *
    + * + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag + * up to 8 characters in length. See the Locale class description about + * valid language values. + * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code. + * See the Locale class description about valid country values. + * @param variant Any arbitrary value used to indicate a variation of a Locale. + * See the Locale class description for the details. + * @exception NullPointerException thrown if any argument is null. + */ + public Locale(String language, String country, String variant) { + _baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant); + _extensions = getCompatibilityExtensions(language, "", country, variant); + } + + /** + * Construct a locale from language and country. + * This constructor normalizes the language value to lowercase and + * the country value to uppercase. + *

    + * Note: + *

      + *
    • ISO 639 is not a stable standard; some of the language codes it defines + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other + * API on Locale will return only the OLD codes. + *
    • For backward compatibility reasons, this constructor does not make + * any syntactic checks on the input. + *
    + * + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag + * up to 8 characters in length. See the Locale class description about + * valid language values. + * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code. + * See the Locale class description about valid country values. * @exception NullPointerException thrown if either argument is null. */ public Locale(String language, String country) { @@ -308,11 +601,21 @@ public final class Locale implements Cloneable, Serializable { /** * Construct a locale from a language code. - * NOTE: ISO 639 is not a stable standard; some of the language codes it defines - * (specifically iw, ji, and in) have changed. This constructor accepts both the - * old codes (iw, ji, and in) and the new codes (he, yi, and id), but all other + * This constructor normalizes the language value to lowercase. + *

    + * Note: + *

      + *
    • ISO 639 is not a stable standard; some of the language codes it defines + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other * API on Locale will return only the OLD codes. - * @param language lowercase two-letter ISO-639 code. + *
    • For backward compatibility reasons, this constructor does not make + * any syntactic checks on the input. + *
    + * + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag + * up to 8 characters in length. See the Locale class description about + * valid language values. * @exception NullPointerException thrown if argument is null. * @since 1.4 */ @@ -320,32 +623,6 @@ public final class Locale implements Cloneable, Serializable { this(language, "", ""); } - /** - * Constructs a Locale using language - * and country. This constructor assumes that - * language and contry are interned and - * it is invoked by createSingleton only. (flag is just for - * avoiding the conflict with the public constructors. - */ - private Locale(String language, String country, boolean flag) { - this.language = language; - this.country = country; - this.variant = ""; - } - - /** - * Creates a Locale instance with the given - * language and counry and puts the - * instance under the given key in the cache. This - * method must be called only when initializing the Locale - * constants. - */ - private static Locale createSingleton(String key, String language, String country) { - Locale locale = new Locale(language, country, false); - cache.put(key, locale); - return locale; - } - /** * Returns a Locale constructed from the given * language, country and @@ -354,29 +631,70 @@ public final class Locale implements Cloneable, Serializable { * returned. Otherwise, a new Locale instance is * created and cached. * - * @param language lowercase two-letter ISO-639 code. - * @param country uppercase two-letter ISO-3166 code. + * @param language lowercase 2 to 8 language code. + * @param country uppercase two-letter ISO-3166 code and numric-3 UN M.49 area code. * @param variant vendor and browser specific code. See class description. * @return the Locale instance requested * @exception NullPointerException if any argument is null. */ static Locale getInstance(String language, String country, String variant) { - if (language== null || country == null || variant == null) { + return getInstance(language, "", country, variant, LocaleExtensions.EMPTY_EXTENSIONS); + } + + static Locale getInstance(String language, String script, String country, + String variant, LocaleExtensions extensions) { + if (language== null || script == null || country == null || variant == null) { throw new NullPointerException(); } - StringBuilder sb = new StringBuilder(); - sb.append(language).append('_').append(country).append('_').append(variant); - String key = sb.toString(); - Locale locale = cache.get(key); - if (locale == null) { - locale = new Locale(language, country, variant); - Locale l = cache.putIfAbsent(key, locale); - if (l != null) { - locale = l; - } + if (extensions == null) { + extensions = LocaleExtensions.EMPTY_EXTENSIONS; + } + + if (extensions.equals(LocaleExtensions.EMPTY_EXTENSIONS)) { + extensions = getCompatibilityExtensions(language, script, country, variant); + } + + BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant); + return getInstance(baseloc, extensions); + } + + static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) { + LocaleKey key = new LocaleKey(baseloc, extensions); + return LOCALECACHE.get(key); + } + + private static class Cache extends LocaleObjectCache { + public Cache() { + } + protected Locale createObject(LocaleKey key) { + return new Locale(key._base, key._exts); + } + } + + private static class LocaleKey { + private BaseLocale _base; + private LocaleExtensions _exts; + + private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) { + _base = baseLocale; + _exts = extensions; + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof LocaleKey)) { + return false; + } + LocaleKey other = (LocaleKey)obj; + return _base.equals(other._base) && _exts.equals(other._exts); + } + + public int hashCode() { + return _base.hashCode() ^ _exts.hashCode(); } - return locale; } /** @@ -395,33 +713,105 @@ public final class Locale implements Cloneable, Serializable { // do not synchronize this method - see 4071298 // it's OK if more than one default locale happens to be created if (defaultLocale == null) { - String language, region, country, variant; - language = AccessController.doPrivileged( - new GetPropertyAction("user.language", "en")); - // for compatibility, check for old user.region property - region = AccessController.doPrivileged( - new GetPropertyAction("user.region")); - if (region != null) { - // region can be of form country, country_variant, or _variant - int i = region.indexOf('_'); - if (i >= 0) { - country = region.substring(0, i); - variant = region.substring(i + 1); - } else { - country = region; - variant = ""; - } - } else { - country = AccessController.doPrivileged( - new GetPropertyAction("user.country", "")); - variant = AccessController.doPrivileged( - new GetPropertyAction("user.variant", "")); - } - defaultLocale = getInstance(language, country, variant); + initDefault(); } return defaultLocale; } + /** + * Gets the current value of the default locale for the specified Category + * for this instance of the Java Virtual Machine. + *

    + * The Java Virtual Machine sets the default locale during startup based + * on the host environment. It is used by many locale-sensitive methods + * if no locale is explicitly specified. It can be changed using the + * setDefault(Locale.Category, Locale) method. + * + * @param category - the specified category to get the default locale + * @throws NullPointerException - if category is null + * @return the default locale for the specified Category for this instance + * of the Java Virtual Machine + * @see #setDefault(Locale.Category, Locale) + * @since 1.7 + */ + public static Locale getDefault(Locale.Category category) { + // do not synchronize this method - see 4071298 + // it's OK if more than one default locale happens to be created + switch (category) { + case DISPLAY: + if (defaultDisplayLocale == null) { + initDefault(category); + } + return defaultDisplayLocale; + case FORMAT: + if (defaultFormatLocale == null) { + initDefault(category); + } + return defaultFormatLocale; + default: + assert false: "Unknown Category"; + } + return getDefault(); + } + + private static void initDefault() { + String language, region, country, variant; + language = AccessController.doPrivileged( + new GetPropertyAction("user.language", "en")); + // for compatibility, check for old user.region property + region = AccessController.doPrivileged( + new GetPropertyAction("user.region")); + if (region != null) { + // region can be of form country, country_variant, or _variant + int i = region.indexOf('_'); + if (i >= 0) { + country = region.substring(0, i); + variant = region.substring(i + 1); + } else { + country = region; + variant = ""; + } + } else { + country = AccessController.doPrivileged( + new GetPropertyAction("user.country", "")); + variant = AccessController.doPrivileged( + new GetPropertyAction("user.variant", "")); + } + defaultLocale = getInstance(language, country, variant); + } + + private static void initDefault(Locale.Category category) { + String language, region, country, variant; + switch (category) { + case DISPLAY: + language = AccessController.doPrivileged( + new GetPropertyAction("user.language.display", "")); + if ("".equals(language)) { + defaultDisplayLocale = getDefault(); + } else { + country = AccessController.doPrivileged( + new GetPropertyAction("user.country.display", "")); + variant = AccessController.doPrivileged( + new GetPropertyAction("user.variant.display", "")); + defaultDisplayLocale = getInstance(language, country, variant); + } + break; + case FORMAT: + language = AccessController.doPrivileged( + new GetPropertyAction("user.language.format", "")); + if ("".equals(language)) { + defaultFormatLocale = getDefault(); + } else { + country = AccessController.doPrivileged( + new GetPropertyAction("user.country.format", "")); + variant = AccessController.doPrivileged( + new GetPropertyAction("user.variant.format", "")); + defaultFormatLocale = getInstance(language, country, variant); + } + break; + } + } + /** * Sets the default locale for this instance of the Java Virtual Machine. * This does not affect the host locale. @@ -438,6 +828,9 @@ public final class Locale implements Cloneable, Serializable { * of functionality, this method should only be used if the caller * is prepared to reinitialize locale-sensitive code running * within the same Java Virtual Machine. + *

    + * By setting the default locale with this method, all of the default + * locales for each Category are also set to the specified default locale. * * @throws SecurityException * if a security manager exists and its @@ -448,13 +841,59 @@ public final class Locale implements Cloneable, Serializable { * @see java.util.PropertyPermission */ public static synchronized void setDefault(Locale newLocale) { + setDefault(Category.DISPLAY, newLocale); + setDefault(Category.FORMAT, newLocale); + defaultLocale = newLocale; + } + + /** + * Sets the default locale for the specified Category for this instance + * of the Java Virtual Machine. This does not affect the host locale. + *

    + * If there is a security manager, its checkPermission method is called + * with a PropertyPermission("user.language", "write") permission before + * the default locale is changed. + *

    + * The Java Virtual Machine sets the default locale during startup based + * on the host environment. It is used by many locale-sensitive methods + * if no locale is explicitly specified. + *

    + * Since changing the default locale may affect many different areas of + * functionality, this method should only be used if the caller is + * prepared to reinitialize locale-sensitive code running within the + * same Java Virtual Machine. + *

    + * + * @param category - the specified category to set the default locale + * @param newLocale - the new default locale + * @throws SecurityException - if a security manager exists and its + * checkPermission method doesn't allow the operation. + * @throws NullPointerException - if category and/or newLocale is null + * @see SecurityManager.checkPermission(java.security.Permission) + * @see PropertyPermission + * @see #getDefault(Locale.Category) + * @since 1.7 + */ + public static synchronized void setDefault(Locale.Category category, + Locale newLocale) { + if (category == null) + throw new NullPointerException("Category cannot be NULL"); if (newLocale == null) throw new NullPointerException("Can't set default locale to NULL"); SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(new PropertyPermission ("user.language", "write")); - defaultLocale = newLocale; + switch (category) { + case DISPLAY: + defaultDisplayLocale = newLocale; + break; + case FORMAT: + defaultFormatLocale = newLocale; + break; + default: + assert false: "Unknown Category"; + } } /** @@ -474,6 +913,11 @@ public final class Locale implements Cloneable, Serializable { /** * Returns a list of all 2-letter country codes defined in ISO 3166. * Can be used to create Locales. + *

    + * Note: The Locale class also supports other codes for + * country (region), such as 3-letter numeric UN M.49 area codes. + * Therefore, the list returned by this method does not contain ALL valid + * codes that can be used to create Locales. */ public static String[] getISOCountries() { if (isoCountries == null) { @@ -487,9 +931,16 @@ public final class Locale implements Cloneable, Serializable { /** * Returns a list of all 2-letter language codes defined in ISO 639. * Can be used to create Locales. - * [NOTE: ISO 639 is not a stable standard-- some languages' codes have changed. + *

    + * Note: + *

      + *
    • ISO 639 is not a stable standard— some languages' codes have changed. * The list this function returns includes both the new and the old codes for the - * languages whose codes have changed.] + * languages whose codes have changed. + *
    • The Locale class also supports language codes up to + * 8 characters in length. Therefore, the list returned by this method does + * not contain ALL valid codes that can be used to create Locales. + *
    */ public static String[] getISOLanguages() { if (isoLanguages == null) { @@ -510,100 +961,516 @@ public final class Locale implements Cloneable, Serializable { } /** - * Returns the language code for this locale, which will either be the empty string - * or a lowercase ISO 639 code. - *

    NOTE: ISO 639 is not a stable standard-- some languages' codes have changed. + * Returns the language code of this Locale. + * + *

    Note: ISO 639 is not a stable standard— some languages' codes have changed. * Locale's constructor recognizes both the new and the old codes for the languages * whose codes have changed, but this function always returns the old code. If you - * want to check for a specific language whose code has changed, don't do

    -     * if (locale.getLanguage().equals("he"))
    +     * want to check for a specific language whose code has changed, don't do
    +     * 
    +     * if (locale.getLanguage().equals("he")) // BAD!
          *    ...
    -     * 
    Instead, do
    -     * if (locale.getLanguage().equals(new Locale("he", "", "").getLanguage()))
    -     *    ...
    + *
    + * Instead, do + *
    +     * if (locale.getLanguage().equals(new Locale("he").getLanguage()))
    +     *    ...
    +     * 
    + * @return The language code, or the empty string if none is defined. * @see #getDisplayLanguage */ public String getLanguage() { - return language; + return _baseLocale.getLanguage(); } /** - * Returns the country/region code for this locale, which will - * either be the empty string or an uppercase ISO 3166 2-letter code. + * Returns the script for this locale, which should + * either be the empty string or an ISO 15924 4-letter script + * code. The first letter is uppercase and the rest are + * lowercase, for example, 'Latn', 'Cyrl'. + * + * @return The script code, or the empty string if none is defined. + * @see #getDisplayScript + * @since 1.7 + */ + public String getScript() { + return _baseLocale.getScript(); + } + + /** + * Returns the country/region code for this locale, which should + * either be the empty string, an uppercase ISO 3166 2-letter code, + * or a UN M.49 3-digit code. + * + * @return The country/region code, or the empty string if none is defined. * @see #getDisplayCountry */ public String getCountry() { - return country; + return _baseLocale.getRegion(); } /** * Returns the variant code for this locale. + * + * @return The variant code, or the empty string if none is defined. * @see #getDisplayVariant */ public String getVariant() { - return variant; + return _baseLocale.getVariant(); } /** - * Getter for the programmatic name of the entire locale, - * with the language, country and variant separated by underbars. - * Language is always lower case, and country is always upper case. - * If the language is missing, the string will begin with an underbar. - * If both the language and country fields are missing, this function - * will return the empty string, even if the variant field is filled in - * (you can't have a locale with just a variant-- the variant must accompany - * a valid language or country code). - * Examples: "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr__MAC" + * Returns the extension (or private use) value associated with + * the specified key, or null if there is no extension + * associated with the key. To be well-formed, the key must be one + * of [0-9A-Za-z]. Keys are case-insensitive, so + * for example 'z' and 'Z' represent the same extension. + * + * @param key the extension key + * @return The extension, or null if this locale defines no + * extension for the specified key. + * @throws IllegalArgumentException if key is not well-formed + * @see #PRIVATE_USE_EXTENSION + * @see #UNICODE_LOCALE_EXTENSION + * @since 1.7 + */ + public String getExtension(char key) { + if (!LocaleExtensions.isValidKey(key)) { + throw new IllegalArgumentException("Ill-formed extension key: " + key); + } + return _extensions.getExtensionValue(key); + } + + /** + * Returns the set of extension keys associated with this locale, or the + * empty set if it has no extensions. The returned set is unmodifiable. + * The keys will all be lower-case. + * + * @return The set of extension keys, or the empty set if this locale has + * no extensions. + * @since 1.7 + */ + public Set getExtensionKeys() { + return _extensions.getKeys(); + } + + /** + * Returns the set of unicode locale attributes associated with + * this locale, or the empty set if it has no attributes. The + * returned set is unmodifiable. + * + * @return The set of attributes. + * @since 1.7 + */ + public Set getUnicodeLocaleAttributes() { + return _extensions.getUnicodeLocaleAttributes(); + } + + /** + * Returns the Unicode locale type associated with the specified Unicode locale key + * for this locale. Returns the empty string for keys that are defined with no type. + * Returns null if the key is not defined. Keys are case-insensitive. The key must + * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is + * thrown. + * + * @param key the Unicode locale key + * @return The Unicode locale type associated with the key, or null if the + * locale does not define the key. + * @throws IllegalArgumentException if the key is not well-formed + * @throws NullPointerException if key is null + * @since 1.7 + */ + public String getUnicodeLocaleType(String key) { + if (!UnicodeLocaleExtension.isKey(key)) { + throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key); + } + return _extensions.getUnicodeLocaleType(key); + } + + /** + * Returns the set of Unicode locale keys defined by this locale, or the empty set if + * this locale has none. The returned set is immutable. Keys are all lower case. + * + * @return The set of Unicode locale keys, or the empty set if this locale has + * no Unicode locale keywords. + * @since 1.7 + */ + public Set getUnicodeLocaleKeys() { + return _extensions.getUnicodeLocaleKeys(); + } + + /** + * Package locale method returning the Locale's BaseLocale, + * used by ResourceBundle + * @return base locale of this Locale + */ + BaseLocale getBaseLocale() { + return _baseLocale; + } + + /** + * Package local method returning the Locale's LocaleExtensions, + * used by ResourceBundle + * @return locale exnteions of this Locale + */ + LocaleExtensions getLocaleExtensions() { + return _extensions; + } + + /** + * Returns a string representation of this Locale + * object, consisting of language, country, variant, script, + * and extensions as below: + *

    + * language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions + *
    + * + * Language is always lower case, country is always upper case, script is always title + * case, and extensions are always lower case. Extensions and private use subtags + * will be in canonical order as explained in {@link #toLanguageTag}. + * + *

    When the locale has neither script nor extensions, the result is the same as in + * Java 6 and prior. + * + *

    If both the language and country fields are missing, this function will return + * the empty string, even if the variant, script, or extensions field is present (you + * can't have a locale with just a variant, the variant must accompany a well-formed + * language or country code). + * + *

    If script or extensions are present and variant is missing, no underscore is + * added before the "#". + * + *

    This behavior is designed to support debugging and to be compatible with + * previous uses of toString that expected language, country, and variant + * fields only. To represent a Locale as a String for interchange purposes, use + * {@link #toLanguageTag}. + * + *

    Examples:

      + *
    • en + *
    • de_DE + *
    • _GB + *
    • en_US_WIN + *
    • de__POSIX + *
    • zh_CN_#Hans + *
    • zh_TW_#Hant-x-java + *
    • th_TH_TH_#u-nu-thai
    + * + * @return A string representation of the Locale, for debugging. * @see #getDisplayName + * @see #toLanguageTag */ public final String toString() { - boolean l = language.length() != 0; - boolean c = country.length() != 0; - boolean v = variant.length() != 0; - StringBuilder result = new StringBuilder(language); - if (c||(l&&v)) { - result.append('_').append(country); // This may just append '_' + boolean l = (_baseLocale.getLanguage().length() != 0); + boolean s = (_baseLocale.getScript().length() != 0); + boolean r = (_baseLocale.getRegion().length() != 0); + boolean v = (_baseLocale.getVariant().length() != 0); + boolean e = (_extensions.getID().length() != 0); + + StringBuilder result = new StringBuilder(_baseLocale.getLanguage()); + if (r || (l && v)) { + result.append('_') + .append(_baseLocale.getRegion()); // This may just append '_' } - if (v&&(l||c)) { - result.append('_').append(variant); + if (v && (l || r)) { + result.append('_') + .append(_baseLocale.getVariant()); } + + if (s && (l || r)) { + result.append("_#") + .append(_baseLocale.getScript()); + } + + if (e && (l || r)) { + result.append('_'); + if (!s) { + result.append('#'); + } + result.append(_extensions.getID()); + } + return result.toString(); } /** - * Returns a three-letter abbreviation for this locale's language. If the locale - * doesn't specify a language, this will be the empty string. Otherwise, this will - * be a lowercase ISO 639-2/T language code. - * The ISO 639-2 language codes can be found on-line at - * - * http://www.loc.gov/standards/iso639-2/englangn.html. - * @exception MissingResourceException Throws MissingResourceException if the + * Returns a well-formed IETF BCP 47 language tag representing + * this locale. + * + *

    If this Locale has a language, country, or + * variant that does not satisfy the IETF BCP 47 language tag + * syntax requirements, this method handles these fields as + * described below: + * + *

    Language: If language is empty, or not well-formed (for example "a" or + * "e2"), it will be emitted as "und" (Undetermined). + * + *

    Country: If country is not well-formed (for example "12" or "USA"), + * it will be omitted. + * + *

    Variant: If variant is well-formed, each sub-segment + * (delimited by '-' or '_') is emitted as a subtag. Otherwise: + *

      + * + *
    • if all sub-segments match [0-9a-zA-Z]{1,8} + * (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first + * ill-formed sub-segment and all following will be appended to + * the private use subtag. The first appended subtag will be + * "lvariant", followed by the sub-segments in order, separated by + * hyphen. For example, "x-lvariant-WIN", + * "Oracle-x-lvariant-JDK-Standard-Edition". + * + *
    • if any sub-segment does not match + * [0-9a-zA-Z]{1,8}, the variant will be truncated + * and the problematic sub-segment and all following sub-segments + * will be omitted. If the remainder is non-empty, it will be + * emitted as a private use subtag as above (even if the remainder + * turns out to be well-formed). For example, + * "Solaris_isjustthecoolestthing" is emitted as + * "x-lvariant-Solaris", not as "solaris".
    + * + *

    Compatibility special cases:

      + * + *
    • The language codes "iw", "ji", and "in" are handled + * specially. Java uses these deprecated codes for compatibility + * reasons. The toLanguageTag method converts these + * three codes (and only these three) to "he", "yi", and "id" + * respectively. + * + *
    • A locale with language "no", country "NO", and variant + * "NY", representing Norwegian Nynorsk, will be represented as + * having language "nn", country "NO", and empty variant. This is + * because some JVMs used the deprecated form to represent the + * user's default locale, and for compatibility reasons that Take a has + * not been changed.
    + * + *

    Note: Although the language tag created by this + * method is well-formed (satisfies the syntax requirements + * defined by the IETF BCP 47 specification), it is not + * necessarily a valid BCP 47 language tag. For example, + *

    +     *   new Locale("xx", "YY").toLanguageTag();
    + * + * will return "xx-YY", but the language subtag "xx" and the + * region subtag "YY" are invalid because they are not registered + * in the IANA Language Subtag Registry. + * + * @return a BCP47 language tag representing the locale + * @see #forLanguageTag(String) + * @since 1.7 + */ + public String toLanguageTag() { + LanguageTag tag = LanguageTag.parseLocale(_baseLocale, _extensions); + StringBuilder buf = new StringBuilder(); + + String subtag = tag.getLanguage(); + buf.append(LanguageTag.canonicalizeLanguage(subtag)); + + subtag = tag.getScript(); + if (subtag.length() > 0) { + buf.append(LanguageTag.SEP); + buf.append(LanguageTag.canonicalizeScript(subtag)); + } + + subtag = tag.getRegion(); + if (subtag.length() > 0) { + buf.append(LanguageTag.SEP); + buf.append(LanguageTag.canonicalizeRegion(subtag)); + } + + Listsubtags = tag.getVariants(); + for (String s : subtags) { + buf.append(LanguageTag.SEP); + // preserve casing + buf.append(s); + } + + subtags = tag.getExtensions(); + for (String s : subtags) { + buf.append(LanguageTag.SEP); + buf.append(LanguageTag.canonicalizeExtension(s)); + } + + subtag = tag.getPrivateuse(); + if (subtag.length() > 0) { + buf.append(LanguageTag.SEP).append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP); + // preserve casing + buf.append(subtag); + } + + return buf.toString(); + } + + /** + * Returns a locale for the specified IETF BCP 47 language tag string. + * + *

    If the specified language tag contains any ill-formed subtags, + * the first such subtag and all following subtags are ignored. Compare + * to {@link Locale.Builder#setLanguageTag} which throws an exception + * in this case. + * + *

    The following conversions are performed:

      + * + *
    • The language code "und" is mapped to language "". + * + *
    • The language codes "he", "yi", and "id" are mapped to "iw", + * "ji", and "in" respectively. (This is the same canonicalization + * that's done in Locale's constructors.) + * + *
    • The portion of a private use subtag prefixed by "lvariant", + * if any, is removed and appended to the variant field in the + * result locale (without case normalization). If it is then + * empty, the private use subtag is discarded: + * + *
      +     *     Locale loc;
      +     *     loc = Locale.forLanguageTag("en-US-x-lvariant-POSIX);
      +     *     loc.getVariant(); // returns "POSIX"
      +     *     loc.getExtension('x'); // returns null
      +     *
      +     *     loc = Locale.forLanguageTag("de-POSIX-x-URP-lvariant-Abc-Def");
      +     *     loc.getVariant(); // returns "POSIX_Abc_Def"
      +     *     loc.getExtension('x'); // returns "urp"
      +     * 
      + * + *
    • When the languageTag argument contains an extlang subtag, + * the first such subtag is used as the language, and the primary + * language subtag and other extlang subtags are ignored: + * + *
      +     *     Locale.forLanguageTag("ar-aao").getLanguage(); // returns "aao"
      +     *     Locale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US"
      +     * 
      + * + *
    • Case is normalized except for variant tags, which are left + * unchanged. Language is normalized to lower case, script to + * title case, country to upper case, and extensions to lower + * case. + * + *
    • If, after processing, the locale would exactly match either + * ja_JP_JP or th_TH_TH with no extensions, the appropriate + * extensions are added as though the constructor had been called: + * + *
      +     *    Locale.forLanguageTag("ja-JP-x-lvariant-JP).toLanguageTag();
      +     *    // returns ja-JP-u-ca-japanese-x-lvariant-JP
      +     *    Locale.forLanguageTag("th-TH-x-lvariant-TH).toLanguageTag();
      +     *    // returns th-TH-u-nu-thai-x-lvariant-TH
      +     * 
    + * + *

    This implements the 'Language-Tag' production of BCP47, and + * so supports grandfathered (regular and irregular) as well as + * private use language tags. Stand alone private use tags are + * represented as empty language and extension 'x-whatever', + * and grandfathered tags are converted to their canonical replacements + * where they exist. + * + *

    Grandfathered tags with canonical replacements are as follows: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    grandfathered tag modern replacement
    art-lojban jbo
    i-ami ami
    i-bnn bnn
    i-hak hak
    i-klingon tlh
    i-lux lb
    i-navajo nv
    i-pwn pwn
    i-tao tao
    i-tay tay
    i-tsu tsu
    no-bok nb
    no-nyn nn
    sgn-BE-FR sfb
    sgn-BE-NL vgt
    sgn-CH-DE sgg
    zh-guoyu cmn
    zh-hakka hak
    zh-min-nan nan
    zh-xiang hsn
    + * + *

    Grandfathered tags with no modern replacement will be + * converted as follows: + * + * + * + * + * + * + * + * + * + * + * + *
    grandfathered tag converts to
    cel-gaulish xtg-x-cel-gaulish
    en-GB-oed en-GB-x-oed
    i-default en-x-i-default
    i-enochian und-x-i-enochian
    i-mingo see-x-i-mingo
    zh-min nan-x-zh-min
    + * + *

    For a list of all grandfathered tags, see the + * IANA Language Subtag Registry (search for "Type: grandfathered"). + * + *

    Note: there is no guarantee that toLanguageTag + * and forLanguageTag will round-trip. + * + * @param languageTag the language tag + * @return The locale that best represents the language tag. + * @throws NullPointerException if languageTag is null + * @see #toLanguageTag() + * @see java.util.Locale.Builder#setLanguageTag(String) + * @since 1.7 + */ + public static Locale forLanguageTag(String languageTag) { + LanguageTag tag = LanguageTag.parse(languageTag, null); + InternalLocaleBuilder bldr = new InternalLocaleBuilder(); + bldr.setLanguageTag(tag); + return getInstance(bldr.getBaseLocale(), bldr.getLocaleExtensions()); + } + + /** + * Returns a three-letter abbreviation of this locale's language. + * If the language matches an ISO 639-1 two-letter code, the + * corresponding ISO 639-2/T three-letter lowercase code is + * returned. The ISO 639-2 language codes can be found on-line, + * see "Codes for the Representation of Names of Languages Part 2: + * Alpha-3 Code". If the locale specifies a three-letter + * language, the language is returned as is. If the locale does + * not specify a language the empty string is returned. + * + * @return A three-letter abbreviation of this locale's language. + * @exception MissingResourceException Throws MissingResourceException if * three-letter language abbreviation is not available for this locale. */ public String getISO3Language() throws MissingResourceException { - String language3 = getISO3Code(language, LocaleISOData.isoLanguageTable); + String language3 = getISO3Code(_baseLocale.getLanguage(), LocaleISOData.isoLanguageTable); if (language3 == null) { throw new MissingResourceException("Couldn't find 3-letter language code for " - + language, "FormatData_" + toString(), "ShortLanguage"); + + _baseLocale.getLanguage(), "FormatData_" + toString(), "ShortLanguage"); } return language3; } /** - * Returns a three-letter abbreviation for this locale's country. If the locale - * doesn't specify a country, this will be the empty string. Otherwise, this will - * be an uppercase ISO 3166 3-letter country code. - * The ISO 3166-2 country codes can be found on-line at - * - * http://www.davros.org/misc/iso3166.txt. + * Returns a three-letter abbreviation for this locale's country. + * If the country matches an ISO 3166-1 alpha-2 code, the + * corresponding ISO 3166-1 alpha-3 uppercase code is returned. + * If the locale doesn't specify a country, this will be the empty + * string. + * + *

    The ISO 3166-1 codes can be found on-line. + * + * @return A three-letter abbreviation of this locale's country. * @exception MissingResourceException Throws MissingResourceException if the * three-letter country abbreviation is not available for this locale. */ public String getISO3Country() throws MissingResourceException { - String country3 = getISO3Code(country, LocaleISOData.isoCountryTable); + String country3 = getISO3Code(_baseLocale.getRegion(), LocaleISOData.isoCountryTable); if (country3 == null) { throw new MissingResourceException("Couldn't find 3-letter country code for " - + country, "FormatData_" + toString(), "ShortCountry"); + + _baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry"); } return country3; } @@ -642,7 +1509,7 @@ public final class Locale implements Cloneable, Serializable { * value. If the locale doesn't specify a language, this function returns the empty string. */ public final String getDisplayLanguage() { - return getDisplayLanguage(getDefault()); + return getDisplayLanguage(getDefault(Category.DISPLAY)); } /** @@ -661,7 +1528,33 @@ public final class Locale implements Cloneable, Serializable { * @exception NullPointerException if inLocale is null */ public String getDisplayLanguage(Locale inLocale) { - return getDisplayString(language, inLocale, DISPLAY_LANGUAGE); + return getDisplayString(_baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE); + } + + /** + * Returns a name for the the locale's script that is appropriate for display to + * the user. If possible, the name will be localized for the default locale. Returns + * the empty string if this locale doesn't specify a script code. + * + * @return the display name of the script code for the current default locale + * @since 1.7 + */ + public String getDisplayScript() { + return getDisplayScript(getDefault()); + } + + /** + * Returns a name for the locale's script that is appropriate + * for display to the user. If possible, the name will be + * localized for the given locale. Returns the empty string if + * this locale doesn't specify a script code. + * + * @return the display name of the script code for the current default locale + * @throws NullPointerException if inLocale is null + * @since 1.7 + */ + public String getDisplayScript(Locale inLocale) { + return getDisplayString(_baseLocale.getScript(), inLocale, DISPLAY_SCRIPT); } /** @@ -677,7 +1570,7 @@ public final class Locale implements Cloneable, Serializable { * value. If the locale doesn't specify a country, this function returns the empty string. */ public final String getDisplayCountry() { - return getDisplayCountry(getDefault()); + return getDisplayCountry(getDefault(Category.DISPLAY)); } /** @@ -696,7 +1589,7 @@ public final class Locale implements Cloneable, Serializable { * @exception NullPointerException if inLocale is null */ public String getDisplayCountry(Locale inLocale) { - return getDisplayString(country, inLocale, DISPLAY_COUNTRY); + return getDisplayString(_baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY); } private String getDisplayString(String code, Locale inLocale, int type) { @@ -744,7 +1637,7 @@ public final class Locale implements Cloneable, Serializable { * doesn't specify a variant code, this function returns the empty string. */ public final String getDisplayVariant() { - return getDisplayVariant(getDefault()); + return getDisplayVariant(getDefault(Category.DISPLAY)); } /** @@ -755,7 +1648,7 @@ public final class Locale implements Cloneable, Serializable { * @exception NullPointerException if inLocale is null */ public String getDisplayVariant(Locale inLocale) { - if (variant.length() == 0) + if (_baseLocale.getVariant().length() == 0) return ""; OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale); @@ -776,39 +1669,44 @@ public final class Locale implements Cloneable, Serializable { /** * Returns a name for the locale that is appropriate for display to the - * user. This will be the values returned by getDisplayLanguage(), getDisplayCountry(), - * and getDisplayVariant() assembled into a single string. The display name will have - * one of the following forms:

    - * language (country, variant)

    - * language (country)

    - * language (variant)

    - * country (variant)

    - * language

    - * country

    - * variant

    - * depending on which fields are specified in the locale. If the language, country, - * and variant fields are all empty, this function returns the empty string. + * user. This will be the values returned by getDisplayLanguage(), + * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled + * into a single string. The the non-empty values are used in order, + * with the second and subsequent names in parentheses. For example: + *
    + * language (script, country, variant)
    + * language (country)
    + * language (variant)
    + * script (country)
    + * country
    + *
    + * depending on which fields are specified in the locale. If the + * language, sacript, country, and variant fields are all empty, + * this function returns the empty string. */ public final String getDisplayName() { - return getDisplayName(getDefault()); + return getDisplayName(getDefault(Category.DISPLAY)); } /** - * Returns a name for the locale that is appropriate for display to the - * user. This will be the values returned by getDisplayLanguage(), getDisplayCountry(), - * and getDisplayVariant() assembled into a single string. The display name will have - * one of the following forms:

    - * language (country, variant)

    - * language (country)

    - * language (variant)

    - * country (variant)

    - * language

    - * country

    - * variant

    - * depending on which fields are specified in the locale. If the language, country, - * and variant fields are all empty, this function returns the empty string. + * Returns a name for the locale that is appropriate for display + * to the user. This will be the values returned by + * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(), + * and getDisplayVariant() assembled into a single string. + * The non-empty values are used in order, + * with the second and subsequent names in parentheses. For example: + *
    + * language (script, country, variant)
    + * language (country)
    + * language (variant)
    + * script (country)
    + * country
    + *
    + * depending on which fields are specified in the locale. If the + * language, script, country, and variant fields are all empty, + * this function returns the empty string. * - * @exception NullPointerException if inLocale is null + * @throws NullPointerException if inLocale is null */ public String getDisplayName(Locale inLocale) { OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale); @@ -888,7 +1786,7 @@ public final class Locale implements Cloneable, Serializable { } /** - * Overrides Cloneable + * Overrides Cloneable. */ public Object clone() { @@ -908,7 +1806,7 @@ public final class Locale implements Cloneable, Serializable { public int hashCode() { int hc = hashCodeValue; if (hc == 0) { - hc = (language.hashCode() << 8) ^ country.hashCode() ^ (variant.hashCode() << 4); + hc = _baseLocale.hashCode() ^ _extensions.hashCode(); hashCodeValue = hc; } return hc; @@ -918,8 +1816,8 @@ public final class Locale implements Cloneable, Serializable { /** * Returns true if this Locale is equal to another object. A Locale is - * deemed equal to another Locale with identical language, country, - * and variant, and unequal to all other objects. + * deemed equal to another Locale with identical language, script, country, + * variant and extensions, and unequal to all other objects. * * @return true if this Locale is equal to the specified object. */ @@ -929,47 +1827,24 @@ public final class Locale implements Cloneable, Serializable { return true; if (!(obj instanceof Locale)) return false; - Locale other = (Locale) obj; - return language == other.language - && country == other.country - && variant == other.variant; + BaseLocale otherBase = ((Locale)obj)._baseLocale; + LocaleExtensions otherExt = ((Locale)obj)._extensions; + return _baseLocale.equals(otherBase) && _extensions.equals(otherExt); } // ================= privates ===================================== - // XXX instance and class variables. For now keep these separate, since it is - // faster to match. Later, make into single string. + private transient BaseLocale _baseLocale; + private transient LocaleExtensions _extensions; /** - * @serial - * @see #getLanguage - */ - private final String language; - - /** - * @serial - * @see #getCountry - */ - private final String country; - - /** - * @serial - * @see #getVariant - */ - private final String variant; - - /** - * Placeholder for the object's hash code. Always -1. - * @serial - */ - private volatile int hashcode = -1; // lazy evaluate - - /** - * Calculated hashcode to fix 4518797. + * Calculated hashcode */ private transient volatile int hashCodeValue = 0; private static Locale defaultLocale = null; + private static Locale defaultDisplayLocale = null; + private static Locale defaultFormatLocale = null; /** * Return an array of the display names of the variant. @@ -978,7 +1853,7 @@ public final class Locale implements Cloneable, Serializable { */ private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) { // Split the variant name into tokens separated by '_'. - StringTokenizer tokenizer = new StringTokenizer(variant, "_"); + StringTokenizer tokenizer = new StringTokenizer(_baseLocale.getVariant(), "_"); String[] names = new String[tokenizer.countTokens()]; // For each variant token, lookup the display name. If @@ -1056,49 +1931,102 @@ public final class Locale implements Cloneable, Serializable { } /** - * Replace the deserialized Locale object with a newly - * created object. Newer language codes are replaced with older ISO - * codes. The country and variant codes are replaced with internalized - * String copies. + * @serialField language String + * language subtag in lower case. (See getLanguage()) + * @serialField country String + * country subtag in upper case. (See getCountry()) + * @serialField variant String + * variant subtags separated by LOWLINE characters. (See getVariant()) + * @serialField hashcode int + * deprectated, for forward compatibility only + * @serialField script String + * script subtag in title case (See getScript()) + * @serialField extensions String + * canonical representation of extensions, that is, + * BCP47 extensions in alphabetical order followed by + * BCP47 private use subtags, all in lower case letters + * separated by HYPHEN-MINUS characters. + * (See getExtensionKeys(), + * getExtension(char)) + */ + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("language", String.class), + new ObjectStreamField("country", String.class), + new ObjectStreamField("variant", String.class), + new ObjectStreamField("hashcode", int.class), + new ObjectStreamField("script", String.class), + new ObjectStreamField("extensions", String.class), + }; + + /** + * Serializes this Locale to the specified ObjectOutputStream. + * @param out the ObjectOutputStream to write + * @throws IOException + * @since 1.7 + */ + private void writeObject(ObjectOutputStream out) throws IOException { + ObjectOutputStream.PutField fields = out.putFields(); + fields.put("language", _baseLocale.getLanguage()); + fields.put("script", _baseLocale.getScript()); + fields.put("country", _baseLocale.getRegion()); + fields.put("variant", _baseLocale.getVariant()); + fields.put("extensions", _extensions.getID()); + fields.put("hashcode", -1); // place holder just for backward support + out.writeFields(); + } + + /** + * Deserialize this Locale. + * @param in the ObjectInputStream to read + * @throws IOException + * @throws ClassNotFoundException + * @throws IllformdLocaleException + * @since 1.7 + */ + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = in.readFields(); + String language = (String)fields.get("language", ""); + String script = (String)fields.get("script", ""); + String country = (String)fields.get("country", ""); + String variant = (String)fields.get("variant", ""); + String extStr = (String)fields.get("extensions", ""); + _baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant); + try { + InternalLocaleBuilder bldr = new InternalLocaleBuilder(); + bldr.setExtensions(extStr); + _extensions = bldr.getLocaleExtensions(); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage()); + } + } + + /** + * Returns a cached Locale instance equivalent to + * the deserialized Locale. When serialized + * language, country and variant fields read from the object data stream + * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions + * fields are empty, this method supplies UNICODE_LOCALE_EXTENSION + * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script + * type is "thai"). See Special Cases + * for more information. + * + * @return an instance of Locale equivalent to + * the deserialized Locale. + * @throws java.io.ObjectStreamException */ private Object readResolve() throws java.io.ObjectStreamException { - return getInstance(language, country, variant); + return getInstance(_baseLocale.getLanguage(), _baseLocale.getScript(), + _baseLocale.getRegion(), _baseLocale.getVariant(), _extensions); } private static volatile String[] isoLanguages = null; private static volatile String[] isoCountries = null; - /* - * Locale needs its own, locale insensitive version of toLowerCase to - * avoid circularity problems between Locale and String. - * The most straightforward algorithm is used. Look at optimizations later. - */ - private String toLowerCase(String str) { - char[] buf = new char[str.length()]; - for (int i = 0; i < buf.length; i++) { - buf[i] = Character.toLowerCase(str.charAt(i)); - } - return new String( buf ); - } - - /* - * Locale needs its own, locale insensitive version of toUpperCase to - * avoid circularity problems between Locale and String. - * The most straightforward algorithm is used. Look at optimizations later. - */ - private String toUpperCase(String str) { - char[] buf = new char[str.length()]; - for (int i = 0; i < buf.length; i++) { - buf[i] = Character.toUpperCase(str.charAt(i)); - } - return new String( buf ); - } - - private String convertOldISOCodes(String language) { + private static String convertOldISOCodes(String language) { // we accept both the old and the new ISO codes for the languages whose ISO // codes have changed, but we always store the OLD code, for backward compatibility - language = toLowerCase(language).intern(); + language = AsciiUtil.toLowerString(language).intern(); if (language == "he") { return "iw"; } else if (language == "yi") { @@ -1110,6 +2038,25 @@ public final class Locale implements Cloneable, Serializable { } } + private static LocaleExtensions getCompatibilityExtensions(String language, String script, String country, String variant) { + LocaleExtensions extensions = LocaleExtensions.EMPTY_EXTENSIONS; + // Special cases for backward compatibility support + if (AsciiUtil.caseIgnoreMatch(language, "ja") + && script.length() == 0 + && AsciiUtil.caseIgnoreMatch(country, "JP") + && AsciiUtil.caseIgnoreMatch(variant, "JP")) { + // ja_JP_JP -> u-ca-japanese (calendar = japanese) + extensions = LocaleExtensions.CALENDAR_JAPANESE; + } else if (AsciiUtil.caseIgnoreMatch(language, "th") + && script.length() == 0 + && AsciiUtil.caseIgnoreMatch(country, "TH") + && AsciiUtil.caseIgnoreMatch(variant, "TH")) { + // th_TH_TH -> u-nu-thai (numbersystem = thai) + extensions = LocaleExtensions.NUMBER_THAI; + } + return extensions; + } + /** * Obtains a localized locale names from a LocaleNameProvider * implementation. @@ -1133,6 +2080,8 @@ public final class Locale implements Cloneable, Serializable { return localeNameProvider.getDisplayCountry(code, locale); case DISPLAY_VARIANT: return localeNameProvider.getDisplayVariant(code, locale); + case DISPLAY_SCRIPT: + return localeNameProvider.getDisplayScript(code, locale); default: assert false; // shouldn't happen } @@ -1140,4 +2089,370 @@ public final class Locale implements Cloneable, Serializable { return null; } } + + /** + * Enum for locale categories. These locale categories are used to get/set + * the default locale for the specific functionality represented by the + * category. + * + * @see #getDefault(Locale.Category) + * @see #setDefault(Locale.Category, Locale) + * @since 1.7 + */ + public enum Category { + + /** + * Category used to represent the default locale for + * displaying user interfaces. + */ + DISPLAY, + + /** + * Category used to represent the default locale for + * formatting dates, numbers, and/or currencies. + */ + FORMAT, + } + + /** + * Builder is used to build instances of Locale + * from values configured by the setters. Unlike the Locale + * constructors, the Builder checks if a value configured by a + * setter satisfies the syntax requirements defined by the Locale + * class. A Locale object created by a Builder is + * well-formed and can be transformed to a well-formed IETF BCP 47 language tag + * without losing information. + * + *

    Note: The Locale class does not provide any + * syntactic restrictions on variant, while BCP 47 requires each variant + * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3 + * alphanumerics. The method setVariant throws + * IllformedLocaleException for a variant that does not satisfy + * this restriction. If it is necessary to support such a variant, use a + * Locale constructor. However, keep in mind that a Locale + * object created this way might lose the variant information when + * transformed to a BCP 47 language tag. + * + *

    The following example shows how to create a Locale object + * with the Builder. + *

    + *
    +     *     Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
    +     * 
    + *
    + * + *

    Builders can be reused; clear() resets all + * fields to their default values. + * + * @see Locale#forLanguageTag + * @since 1.7 + */ + public static final class Builder { + private InternalLocaleBuilder _locbld; + + /** + * Constructs an empty Builder. The default value of all + * fields, extensions, and private use information is the + * empty string. + */ + public Builder() { + _locbld = new InternalLocaleBuilder(); + } + + /** + * Resets the Builder to match the provided + * locale. Existing state is discarded. + * + *

    All fields of the locale must be well-formed, see {@link Locale}. + * + *

    Locales with any ill-formed fields cause + * IllformedLocaleException to be thrown, except for the + * following three cases which are accepted for compatibility + * reasons:

      + *
    • Locale("ja", "JP", "JP") is treated as "ja-JP-u-ca-japanese" + *
    • Locale("th", "TH", "TH") is treated as "th-TH-u-nu-thai" + *
    • Locale("no", "NO", "NY") is treated as "nn-NO"
    + * + * @param locale the locale + * @return This builder. + * @throws IllformedLocaleException if locale has + * any ill-formed fields. + * @throws NullPointerException if locale is null. + */ + public Builder setLocale(Locale locale) { + try { + _locbld.setLocale(locale._baseLocale, locale._extensions); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); + } + return this; + } + + /** + * Resets the Builder to match the provided IETF BCP 47 + * language tag. Discards the existing state. Null and the + * empty string cause the builder to be reset, like {@link + * #clear}. Grandfathered tags (see {@link + * Locale#forLanguageTag}) are converted to their canonical + * form before being processed. Otherwise, the language tag + * must be well-formed (see {@link Locale}) or an exception is + * thrown (unlike Locale.forLanguageTag, which + * just discards ill-formed and following portions of the + * tag). + * + * @param languageTag the language tag + * @return This builder. + * @throws IllformedLocaleException if languageTag is ill-formed + * @see Locale#forLanguageTag(String) + */ + public Builder setLanguageTag(String languageTag) { + ParseStatus sts = new ParseStatus(); + LanguageTag tag = LanguageTag.parse(languageTag, sts); + if (sts.isError()) { + throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex()); + } + _locbld.setLanguageTag(tag); + + return this; + } + + /** + * Sets the language. If language is the empty string or + * null, the language in this Builder is removed. Otherwise, + * the language must be well-formed + * or an exception is thrown. + * + *

    The typical language value is a two or three-letter language + * code as defined in ISO639. + * + * @param language the language + * @return This builder. + * @throws IllformedLocaleException if language is ill-formed + */ + public Builder setLanguage(String language) { + try { + _locbld.setLanguage(language); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); + } + return this; + } + + /** + * Sets the script. If script is null or the empty string, + * the script in this Builder is removed. + * Otherwise, the script must be well-formed or an + * exception is thrown. + * + *

    The typical script value is a four-letter script code as defined by ISO 15924. + * + * @param script the script + * @return This builder. + * @throws IllformedLocaleException if script is ill-formed + */ + public Builder setScript(String script) { + try { + _locbld.setScript(script); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); + } + return this; + } + + /** + * Sets the region. If region is null or the empty string, the region + * in this Builder is removed. Otherwise, + * the region must be well-formed or an + * exception is thrown. + * + *

    The typical region value is a two-letter ISO 3166 code or a + * three-digit UN M.49 area code. + * + *

    The country value in the Locale created by the + * Builder is always normalized to upper case. + * + * @param region the region + * @return This builder. + * @throws IllformedLocaleException if region is ill-formed + */ + public Builder setRegion(String region) { + try { + _locbld.setRegion(region); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); + } + return this; + } + + /** + * Sets the variant. If variant is null or the empty string, the + * variant in this Builder is removed. Otherwise, it + * must consist of one or more well-formed + * subtags, or an exception is thrown. + * + *

    Note: This method checks if variant + * satisfies the IETF BCP 47 variant subtag's syntax requirements, + * and normalizes the value to lowercase letters. However, + * the Locale class does not impose any syntactic + * restriction on variant, and the variant value in + * Locale is case sensitive. To set such a variant, + * use a Locale constructor. + * + * @param variant the variant + * @return This builder. + * @throws IllformedLocaleException if variant is ill-formed + */ + public Builder setVariant(String variant) { + try { + _locbld.setVariant(variant); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); + } + return this; + } + + /** + * Sets the extension for the given key. If the value is null or the + * empty string, the extension is removed. Otherwise, the extension + * must be well-formed or an exception + * is thrown. + * + *

    Note: The key {@link Locale#UNICODE_LOCALE_EXTENSION + * UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension. + * Setting a value for this key replaces any existing Unicode locale key/type + * pairs with those defined in the extension. + * + *

    Note: The key {@link Locale#PRIVATE_USE_EXTENSION + * PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be + * well-formed, the value for this key needs only to have subtags of one to + * eight alphanumeric characters, not two to eight as in the general case. + * + * @param key the extension key + * @param value the extension value + * @return This builder. + * @throws IllformedLocaleException if key is illegal + * or value is ill-formed + * @see #setUnicodeLocaleKeyword(String, String) + */ + public Builder setExtension(char key, String value) { + try { + _locbld.setExtension(key, value); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); + } + return this; + } + + /** + * Sets the Unicode locale keyword type for the given key. If the type + * is null, the Unicode keyword is removed. Otherwise, the key must be + * non-null and both key and type must be well-formed or an exception + * is thrown. + * + *

    Keys and types are converted to lower case. + * + *

    Note:Setting the 'u' extension via {@link #setExtension} + * replaces all Unicode locale keywords with those defined in the + * extension. + * + * @param key the Unicode locale key + * @param type the Unicode locale type + * @return This builder. + * @throws IllformedLocaleException if key or type + * is ill-formed + * @throws NullPointerException if key is null + * @see #setExtension(char, String) + */ + public Builder setUnicodeLocaleKeyword(String key, String type) { + try { + _locbld.setUnicodeLocaleKeyword(key, type); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); + } + return this; + } + + /** + * Adds a unicode locale attribute, if not already present, otherwise + * has no effect. The attribute must not be null and must be well-formed or an exception + * is thrown. + * + * @param attribute the attribute + * @return This builder. + * @throws NullPointerException if attribute is null + * @throws IllformedLocaleException if attribute is ill-formed + * @see #setExtension(char, String) + */ + public Builder addUnicodeLocaleAttribute(String attribute) { + try { + _locbld.addUnicodeLocaleAttribute(attribute); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); + } + return this; + } + + /** + * Removes a unicode locale attribute, if present, otherwise has no + * effect. The attribute must not be null and must be well-formed or an exception + * is thrown. + * + *

    Attribute comparision for removal is case-insensitive. + * + * @param attribute the attribute + * @return This builder. + * @throws NullPointerException if attribute is null + * @throws IllformedLocaleException if attribute is ill-formed + * @see #setExtension(char, String) + */ + public Builder removeUnicodeLocaleAttribute(String attribute) { + try { + _locbld.removeUnicodeLocaleAttribute(attribute); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); + } + return this; + } + + /** + * Resets the builder to its initial, empty state. + * + * @return This builder. + */ + public Builder clear() { + _locbld.clear(); + return this; + } + + /** + * Resets the extensions to their initial, empty state. + * Language, script, region and variant are unchanged. + * + * @return This builder. + * @see #setExtension(char, String) + */ + public Builder clearExtensions() { + _locbld.clearExtensions(); + return this; + } + + /** + * Returns an instance of Locale created from the fields set + * on this builder. + * + *

    This applies the conversions listed in {@link Locale#forLanguageTag} + * when constructing a Locale. (Grandfathered tags are handled in + * {@link #setLanguageTag}.) + * + * @return A Locale. + */ + public Locale build() { + BaseLocale baseloc = _locbld.getBaseLocale(); + LocaleExtensions extensions = _locbld.getLocaleExtensions(); + return Locale.getInstance(baseloc, extensions); + } + } } diff --git a/jdk/src/share/classes/java/util/Properties.java b/jdk/src/share/classes/java/util/Properties.java index 4012f2f5e6c..6f9c562e4f8 100644 --- a/jdk/src/share/classes/java/util/Properties.java +++ b/jdk/src/share/classes/java/util/Properties.java @@ -912,9 +912,13 @@ class Properties extends Hashtable { * *

    The specified stream remains open after this method returns. * - * @param os the output stream on which to emit the XML document. - * @param comment a description of the property list, or null - * if no comment is desired. + * @param os the output stream on which to emit the XML document. + * @param comment a description of the property list, or null + * if no comment is desired. + * @param encoding the name of a supported + * + * character encoding + * * @throws IOException if writing to the specified output stream * results in an IOException. * @throws NullPointerException if os is null, diff --git a/jdk/src/share/classes/java/util/ResourceBundle.java b/jdk/src/share/classes/java/util/ResourceBundle.java index 56888362bbd..e645fe91439 100644 --- a/jdk/src/share/classes/java/util/ResourceBundle.java +++ b/jdk/src/share/classes/java/util/ResourceBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,16 +56,18 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.jar.JarEntry; +import sun.util.locale.BaseLocale; +import sun.util.locale.LocaleExtensions; +import sun.util.locale.LocaleObjectCache; + /** * - * Resource bundles contain locale-specific objects. - * When your program needs a locale-specific resource, - * a String for example, your program can load it - * from the resource bundle that is appropriate for the - * current user's locale. In this way, you can write - * program code that is largely independent of the user's - * locale isolating most, if not all, of the locale-specific + * Resource bundles contain locale-specific objects. When your program needs a + * locale-specific resource, a String for example, your program can + * load it from the resource bundle that is appropriate for the current user's + * locale. In this way, you can write program code that is largely independent + * of the user's locale isolating most, if not all, of the locale-specific * information in resource bundles. * *

    @@ -854,87 +856,140 @@ public abstract class ResourceBundle { } /** - * Gets a resource bundle using the specified base name, locale, and class loader. + * Gets a resource bundle using the specified base name, locale, and class + * loader. * - *

    - * Conceptually, getBundle uses the following strategy for locating and instantiating - * resource bundles: - *

    - * getBundle uses the base name, the specified locale, and the default - * locale (obtained from {@link java.util.Locale#getDefault() Locale.getDefault}) - * to generate a sequence of candidate bundle names. - * If the specified locale's language, country, and variant are all empty - * strings, then the base name is the only candidate bundle name. - * Otherwise, the following sequence is generated from the attribute - * values of the specified locale (language1, country1, and variant1) - * and of the default locale (language2, country2, and variant2): - *

      - *
    • baseName + "_" + language1 + "_" + country1 + "_" + variant1 - *
    • baseName + "_" + language1 + "_" + country1 - *
    • baseName + "_" + language1 - *
    • baseName + "_" + language2 + "_" + country2 + "_" + variant2 - *
    • baseName + "_" + language2 + "_" + country2 - *
    • baseName + "_" + language2 - *
    • baseName - *
    - *

    - * Candidate bundle names where the final component is an empty string are omitted. - * For example, if country1 is an empty string, the second candidate bundle name is omitted. + *

    This method behaves the same as calling + * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a + * default instance of {@link Control}. The following describes this behavior. * - *

    - * getBundle then iterates over the candidate bundle names to find the first - * one for which it can instantiate an actual resource bundle. For each candidate - * bundle name, it attempts to create a resource bundle: - *

    + *

    getBundle uses the base name, the specified locale, and + * the default locale (obtained from {@link java.util.Locale#getDefault() + * Locale.getDefault}) to generate a sequence of candidate bundle names. If the specified + * locale's language, script, country, and variant are all empty strings, + * then the base name is the only candidate bundle name. Otherwise, a list + * of candidate locales is generated from the attribute values of the + * specified locale (language, script, country and variant) and appended to + * the base name. Typically, this will look like the following: * - *

    - * If no result resource bundle has been found, a MissingResourceException - * is thrown. + *

    +     *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
    +     *     baseName + "_" + language + "_" + script + "_" + country
    +     *     baseName + "_" + language + "_" + script
    +     *     baseName + "_" + language + "_" + country + "_" + variant
    +     *     baseName + "_" + language + "_" + country
    +     *     baseName + "_" + language
    +     * 
    * - *

    - * Once a result resource bundle has been found, its parent chain is instantiated. - * getBundle iterates over the candidate bundle names that can be - * obtained by successively removing variant, country, and language - * (each time with the preceding "_") from the bundle name of the result resource bundle. - * As above, candidate bundle names where the final component is an empty string are omitted. - * With each of the candidate bundle names it attempts to instantiate a resource bundle, as - * described above. - * Whenever it succeeds, it calls the previously instantiated resource + *

    Candidate bundle names where the final component is an empty string + * are omitted, along with the underscore. For example, if country is an + * empty string, the second and the fifth candidate bundle names above + * would be omitted. Also, if script is an empty string, the candidate names + * including script are omitted. For example, a locale with language "de" + * and variant "JAVA" will produce candidate names with base name + * "MyResource" below. + * + *

    +     *     MyResource_de__JAVA
    +     *     MyResource_de
    +     * 
    + * + * In the case that the variant contains one or more underscores ('_'), a + * sequence of bundle names generated by truncating the last underscore and + * the part following it is inserted after a candidate bundle name with the + * original variant. For example, for a locale with language "en", script + * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name + * "MyResource", the list of candidate bundle names below is generated: + * + *
    +     * MyResource_en_Latn_US_WINDOWS_VISTA
    +     * MyResource_en_Latn_US_WINDOWS
    +     * MyResource_en_Latn_US
    +     * MyResource_en_Latn
    +     * MyResource_en_US_WINDOWS_VISTA
    +     * MyResource_en_US_WINDOWS
    +     * MyResource_en_US
    +     * MyResource_en
    +     * 
    + * + *
    Note: For some Locales, the list of + * candidate bundle names contains extra names, or the order of bundle names + * is slightly modified. See the description of the default implementation + * of {@link Control#getCandidateLocales(String, Locale) + * getCandidateLocales} for details.
    + * + *

    getBundle then iterates over the candidate bundle names + * to find the first one for which it can instantiate an actual + * resource bundle. It uses the default controls' {@link Control#getFormats + * getFormats} method, which generates two bundle names for each generated + * name, the first a class name and the second a properties file name. For + * each candidate bundle name, it attempts to create a resource bundle: + * + *

    • First, it attempts to load a class using the generated class name. + * If such a class can be found and loaded using the specified class + * loader, is assignment compatible with ResourceBundle, is accessible from + * ResourceBundle, and can be instantiated, getBundle creates a + * new instance of this class and uses it as the result resource + * bundle. + * + *
    • Otherwise, getBundle attempts to locate a property + * resource file using the generated properties file name. It generates a + * path name from the candidate bundle name by replacing all "." characters + * with "/" and appending the string ".properties". It attempts to find a + * "resource" with this name using {@link + * java.lang.ClassLoader#getResource(java.lang.String) + * ClassLoader.getResource}. (Note that a "resource" in the sense of + * getResource has nothing to do with the contents of a + * resource bundle, it is just a container of data, such as a file.) If it + * finds a "resource", it attempts to create a new {@link + * PropertyResourceBundle} instance from its contents. If successful, this + * instance becomes the result resource bundle.
    + * + *

    This continues until a result resource bundle is instantiated or the + * list of candidate bundle names is exhausted. If no matching resource + * bundle is found, the default control's {@link Control#getFallbackLocale + * getFallbackLocale} method is called, which returns the current default + * locale. A new sequence of candidate locale names is generated using this + * locale and and searched again, as above. + * + *

    If still no result bundle is found, the base name alone is looked up. If + * this still fails, a MissingResourceException is thrown. + * + *

    Once a result resource bundle has been found, + * its parent chain is instantiated. If the result bundle already + * has a parent (perhaps because it was returned from a cache) the chain is + * complete. + * + *

    Otherwise, getBundle examines the remainder of the + * candidate locale list that was used during the pass that generated the + * result resource bundle. (As before, candidate bundle names where the + * final component is an empty string are omitted.) When it comes to the + * end of the candidate list, it tries the plain bundle name. With each of the + * candidate bundle names it attempts to instantiate a resource bundle (first + * looking for a class and then a properties file, as described above). + * + *

    Whenever it succeeds, it calls the previously instantiated resource * bundle's {@link #setParent(java.util.ResourceBundle) setParent} method - * with the new resource bundle, unless the previously instantiated resource - * bundle already has a non-null parent. + * with the new resource bundle. This continues until the list of names + * is exhausted or the current bundle already has a non-null parent. * - *

    - * getBundle caches instantiated resource bundles and - * may return the same resource bundle instance multiple - * times. + *

    Once the parent chain is complete, the bundle is returned. * - *

    - * The baseName argument should be a fully qualified class name. However, for - * compatibility with earlier versions, Sun's Java SE Runtime Environments do not verify this, - * and so it is possible to access PropertyResourceBundles by specifying a - * path name (using "/") instead of a fully qualified class name (using "."). + *

    Note: getBundle caches instantiated resource + * bundles and might return the same resource bundle instance multiple times. + * + *

    Note:The baseName argument should be a fully + * qualified class name. However, for compatibility with earlier versions, + * Sun's Java SE Runtime Environments do not verify this, and so it is + * possible to access PropertyResourceBundles by specifying a + * path name (using "/") instead of a fully qualified class name (using + * "."). * *

    - * Example:
    The following class and property files are provided: + * Example: + *

    + * The following class and property files are provided: *

          *     MyResources.class
          *     MyResources.properties
    @@ -944,22 +999,26 @@ public abstract class ResourceBundle {
          *     MyResources_en.properties
          *     MyResources_es_ES.class
          * 
    - * The contents of all files are valid (that is, public non-abstract subclasses of ResourceBundle for - * the ".class" files, syntactically correct ".properties" files). - * The default locale is Locale("en", "GB"). - *

    - * Calling getBundle with the shown locale argument values instantiates - * resource bundles from the following sources: - *

      - *
    • Locale("fr", "CH"): result MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class - *
    • Locale("fr", "FR"): result MyResources_fr.properties, parent MyResources.class - *
    • Locale("de", "DE"): result MyResources_en.properties, parent MyResources.class - *
    • Locale("en", "US"): result MyResources_en.properties, parent MyResources.class - *
    • Locale("es", "ES"): result MyResources_es_ES.class, parent MyResources.class - *
    - *

    The file MyResources_fr_CH.properties is never used because it is hidden by - * MyResources_fr_CH.class. Likewise, MyResources.properties is also hidden by - * MyResources.class. + * + * The contents of all files are valid (that is, public non-abstract + * subclasses of ResourceBundle for the ".class" files, + * syntactically correct ".properties" files). The default locale is + * Locale("en", "GB"). + * + *

    Calling getBundle with the locale arguments below will + * instantiate resource bundles as follows: + * + * + * + * + * + * + * + *
    Locale("fr", "CH")MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class
    Locale("fr", "FR")MyResources_fr.properties, parent MyResources.class
    Locale("de", "DE")MyResources_en.properties, parent MyResources.class
    Locale("en", "US")MyResources_en.properties, parent MyResources.class
    Locale("es", "ES")MyResources_es_ES.class, parent MyResources.class
    + * + *

    The file MyResources_fr_CH.properties is never used because it is + * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties + * is also hidden by MyResources.class. * * @param baseName the base name of the resource bundle, a fully qualified class name * @param locale the locale for which a resource bundle is desired @@ -1095,8 +1154,6 @@ public abstract class ResourceBundle { * href="./ResourceBundle.html#parent_chain">parent chain is * instantiated based on the list of candidate locales from which it was * found. Finally, the bundle is returned to the caller.

  • - * - * * * *

    During the resource bundle loading process above, this factory @@ -1119,7 +1176,6 @@ public abstract class ResourceBundle { * {@link Control#getTimeToLive(String,Locale) * control.getTimeToLive} for details. * - * *

    The following is an example of the bundle loading process with the * default ResourceBundle.Control implementation. * @@ -1131,7 +1187,6 @@ public abstract class ResourceBundle { *

  • Available resource bundles: * foo/bar/Messages_fr.properties and * foo/bar/Messages.properties
  • - * * * *

    First, getBundle tries loading a resource bundle in @@ -1811,8 +1866,8 @@ public abstract class ResourceBundle { * handleGetObject} method returns null. Once the * Set has been created, the value is kept in this * ResourceBundle in order to avoid producing the - * same Set in the next calls. Override this method - * in subclass implementations for faster handling. + * same Set in subsequent calls. Subclasses can + * override this method for faster handling. * * @return a Set of the keys contained only in this * ResourceBundle @@ -2177,24 +2232,133 @@ public abstract class ResourceBundle { * ResourceBundle.getBundle factory method loads only * the base bundle as the resulting resource bundle. * - *

    It is not a requirement to return an immutable - * (unmodifiable) List. However, the returned - * List must not be mutated after it has been - * returned by getCandidateLocales. + *

    It is not a requirement to return an immutable (unmodifiable) + * List. However, the returned List must not + * be mutated after it has been returned by + * getCandidateLocales. * *

    The default implementation returns a List containing - * Locales in the following sequence: - *

    -         *     Locale(language, country, variant)
    -         *     Locale(language, country)
    -         *     Locale(language)
    -         *     Locale.ROOT
    -         * 
    - * where language, country and - * variant are the language, country and variant values - * of the given locale, respectively. Locales where the + * Locales using the rules described below. In the + * description below, L, S, C and V + * respectively represent non-empty language, script, country, and + * variant. For example, [L, C] represents a + * Locale that has non-empty values only for language and + * country. The form L("xx") represents the (non-empty) + * language value is "xx". For all cases, Locales whose * final component values are empty strings are omitted. * + *
    1. For an input Locale with an empty script value, + * append candidate Locales by omitting the final component + * one by one as below: + * + *
        + *
      • [L, C, V] + *
      • [L, C] + *
      • [L] + *
      • Locale.ROOT + *
      + * + *
    2. For an input Locale with a non-empty script value, + * append candidate Locales by omitting the final component + * up to language, then append candidates generated from the + * Locale with country and variant restored: + * + *
        + *
      • [L, S, C, V] + *
      • [L, S, C] + *
      • [L, S] + *
      • [L, C, V] + *
      • [L, C] + *
      • [L] + *
      • Locale.ROOT + *
      + * + *
    3. For an input Locale with a variant value consisting + * of multiple subtags separated by underscore, generate candidate + * Locales by omitting the variant subtags one by one, then + * insert them after every occurence of Locales with the + * full variant value in the original list. For example, if the + * the variant consists of two subtags V1 and V2: + * + *
        + *
      • [L, S, C, V1, V2] + *
      • [L, S, C, V1] + *
      • [L, S, C] + *
      • [L, S] + *
      • [L, C, V1, V2] + *
      • [L, C, V1] + *
      • [L, C] + *
      • [L] + *
      • Locale.ROOT + *
      + * + *
    4. Special cases for Chinese. When an input Locale has the + * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or + * "Hant" (Traditional) might be supplied, depending on the country. + * When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied. + * When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China), + * or "TW" (Taiwan), "Hant" is supplied. For all other countries or when the country + * is empty, no script is supplied. For example, for Locale("zh", "CN") + * , the candidate list will be: + *
        + *
      • [L("zh"), S("Hans"), C("CN")] + *
      • [L("zh"), S("Hans")] + *
      • [L("zh"), C("CN")] + *
      • [L("zh")] + *
      • Locale.ROOT + *
      + * + * For Locale("zh", "TW"), the candidate list will be: + *
        + *
      • [L("zh"), S("Hant"), C("TW")] + *
      • [L("zh"), S("Hant")] + *
      • [L("zh"), C("TW")] + *
      • [L("zh")] + *
      • Locale.ROOT + *
      + * + *
    5. Special cases for Norwegian. Both Locale("no", "NO", + * "NY") and Locale("nn", "NO") represent Norwegian + * Nynorsk. When a locale's language is "nn", the standard candidate + * list is generated up to [L("nn")], and then the following + * candidates are added: + * + *
      • [L("no"), C("NO"), V("NY")] + *
      • [L("no"), C("NO")] + *
      • [L("no")] + *
      • Locale.ROOT + *
      + * + * If the locale is exactly Locale("no", "NO", "NY"), it is first + * converted to Locale("nn", "NO") and then the above procedure is + * followed. + * + *

      Also, Java treats the language "no" as a synonym of Norwegian + * Bokmål "nb". Except for the single case Locale("no", + * "NO", "NY") (handled above), when an input Locale + * has language "no" or "nb", candidate Locales with + * language code "no" and "nb" are interleaved, first using the + * requested language, then using its synonym. For example, + * Locale("nb", "NO", "POSIX") generates the following + * candidate list: + * + *

        + *
      • [L("nb"), C("NO"), V("POSIX")] + *
      • [L("no"), C("NO"), V("POSIX")] + *
      • [L("nb"), C("NO")] + *
      • [L("no"), C("NO")] + *
      • [L("nb")] + *
      • [L("no")] + *
      • Locale.ROOT + *
      + * + * Locale("no", "NO", "POSIX") would generate the same list + * except that locales with "no" would appear before the corresponding + * locales with "nb".
    6. + * + * + *
    + * *

    The default implementation uses an {@link ArrayList} that * overriding implementations may modify before returning it to the * caller. However, a subclass must not modify it after it has @@ -2231,24 +2395,119 @@ public abstract class ResourceBundle { if (baseName == null) { throw new NullPointerException(); } - String language = locale.getLanguage(); - String country = locale.getCountry(); - String variant = locale.getVariant(); + return new ArrayList(CANDIDATES_CACHE.get(locale.getBaseLocale())); + } - List locales = new ArrayList(4); - if (variant.length() > 0) { - locales.add(locale); + private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache(); + + private static class CandidateListCache extends LocaleObjectCache> { + protected List createObject(BaseLocale base) { + String language = base.getLanguage(); + String script = base.getScript(); + String region = base.getRegion(); + String variant = base.getVariant(); + + // Special handling for Norwegian + boolean isNorwegianBokmal = false; + boolean isNorwegianNynorsk = false; + if (language.equals("no")) { + if (region.equals("NO") && variant.equals("NY")) { + variant = ""; + isNorwegianNynorsk = true; + } else { + isNorwegianBokmal = true; + } + } + if (language.equals("nb") || isNorwegianBokmal) { + List tmpList = getDefaultList("nb", script, region, variant); + // Insert a locale replacing "nb" with "no" for every list entry + List bokmalList = new LinkedList(); + for (Locale l : tmpList) { + bokmalList.add(l); + if (l.getLanguage().length() == 0) { + break; + } + bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(), + l.getVariant(), LocaleExtensions.EMPTY_EXTENSIONS)); + } + return bokmalList; + } else if (language.equals("nn") || isNorwegianNynorsk) { + // Insert no_NO_NY, no_NO, no after nn + List nynorskList = getDefaultList("nn", script, region, variant); + int idx = nynorskList.size() - 1; + nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY")); + nynorskList.add(idx++, Locale.getInstance("no", "NO", "")); + nynorskList.add(idx++, Locale.getInstance("no", "", "")); + return nynorskList; + } + // Special handling for Chinese + else if (language.equals("zh")) { + if (script.length() == 0 && region.length() > 0) { + // Supply script for users who want to use zh_Hans/zh_Hant + // as bundle names (recommended for Java7+) + if (region.equals("TW") || region.equals("HK") || region.equals("MO")) { + script = "Hant"; + } else if (region.equals("CN") || region.equals("SG")) { + script = "Hans"; + } + } else if (script.length() > 0 && region.length() == 0) { + // Supply region(country) for users who still package Chinese + // bundles using old convension. + if (script.equals("Hans")) { + region = "CN"; + } else if (script.equals("Hant")) { + region = "TW"; + } + } + } + + return getDefaultList(language, script, region, variant); } - if (country.length() > 0) { - locales.add((locales.size() == 0) ? - locale : Locale.getInstance(language, country, "")); + + private static List getDefaultList(String language, String script, String region, String variant) { + List variants = null; + + if (variant.length() > 0) { + variants = new LinkedList(); + int idx = variant.length(); + while (idx != -1) { + variants.add(variant.substring(0, idx)); + idx = variant.lastIndexOf('_', --idx); + } + } + + LinkedList list = new LinkedList(); + + if (variants != null) { + for (String v : variants) { + list.add(Locale.getInstance(language, script, region, v, LocaleExtensions.EMPTY_EXTENSIONS)); + } + } + if (region.length() > 0) { + list.add(Locale.getInstance(language, script, region, "", LocaleExtensions.EMPTY_EXTENSIONS)); + } + if (script.length() > 0) { + list.add(Locale.getInstance(language, script, "", "", LocaleExtensions.EMPTY_EXTENSIONS)); + + // With script, after truncating variant, region and script, + // start over without script. + if (variants != null) { + for (String v : variants) { + list.add(Locale.getInstance(language, "", region, v, LocaleExtensions.EMPTY_EXTENSIONS)); + } + } + if (region.length() > 0) { + list.add(Locale.getInstance(language, "", region, "", LocaleExtensions.EMPTY_EXTENSIONS)); + } + } + if (language.length() > 0) { + list.add(Locale.getInstance(language, "", "", "", LocaleExtensions.EMPTY_EXTENSIONS)); + } + // Add root locale at the end + list.add(Locale.ROOT); + + return list; } - if (language.length() > 0) { - locales.add((locales.size() == 0) ? - locale : Locale.getInstance(language, "", "")); - } - locales.add(Locale.ROOT); - return locales; } /** @@ -2606,13 +2865,14 @@ public abstract class ResourceBundle { * *

    This implementation returns the following value: *

    -         *     baseName + "_" + language + "_" + country + "_" + variant
    +         *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
              * 
    - * where language, country and - * variant are the language, country and variant values - * of locale, respectively. Final component values that - * are empty Strings are omitted along with the preceding '_'. If - * all of the values are empty strings, then baseName + * where language, script, country, + * and variant are the language, script, country, and variant + * values of locale, respectively. Final component values that + * are empty Strings are omitted along with the preceding '_'. When the + * script is empty, the script value is ommitted along with the preceding '_'. + * If all of the values are empty strings, then baseName * is returned. * *

    For example, if baseName is @@ -2643,6 +2903,7 @@ public abstract class ResourceBundle { } String language = locale.getLanguage(); + String script = locale.getScript(); String country = locale.getCountry(); String variant = locale.getVariant(); @@ -2652,12 +2913,22 @@ public abstract class ResourceBundle { StringBuilder sb = new StringBuilder(baseName); sb.append('_'); - if (variant != "") { - sb.append(language).append('_').append(country).append('_').append(variant); - } else if (country != "") { - sb.append(language).append('_').append(country); + if (script != "") { + if (variant != "") { + sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant); + } else if (country != "") { + sb.append(language).append('_').append(script).append('_').append(country); + } else { + sb.append(language).append('_').append(script); + } } else { - sb.append(language); + if (variant != "") { + sb.append(language).append('_').append(country).append('_').append(variant); + } else if (country != "") { + sb.append(language).append('_').append(country); + } else { + sb.append(language); + } } return sb.toString(); diff --git a/jdk/src/share/classes/java/util/Scanner.java b/jdk/src/share/classes/java/util/Scanner.java index 615250ccc3c..139e5fa38d2 100644 --- a/jdk/src/share/classes/java/util/Scanner.java +++ b/jdk/src/share/classes/java/util/Scanner.java @@ -582,7 +582,7 @@ public final class Scanner implements Iterator, Closeable { matcher = delimPattern.matcher(buf); matcher.useTransparentBounds(true); matcher.useAnchoringBounds(false); - useLocale(Locale.getDefault()); + useLocale(Locale.getDefault(Locale.Category.FORMAT)); } /** @@ -2642,7 +2642,7 @@ public final class Scanner implements Iterator, Closeable { */ public Scanner reset() { delimPattern = WHITESPACE_PATTERN; - useLocale(Locale.getDefault()); + useLocale(Locale.getDefault(Locale.Category.FORMAT)); useRadix(10); clearCaches(); return this; diff --git a/jdk/src/share/classes/java/util/TimeZone.java b/jdk/src/share/classes/java/util/TimeZone.java index 1a68ca3e887..b759f9126d5 100644 --- a/jdk/src/share/classes/java/util/TimeZone.java +++ b/jdk/src/share/classes/java/util/TimeZone.java @@ -312,7 +312,7 @@ abstract public class TimeZone implements Serializable, Cloneable { * @since 1.2 */ public final String getDisplayName() { - return getDisplayName(false, LONG, Locale.getDefault()); + return getDisplayName(false, LONG, Locale.getDefault(Locale.Category.DISPLAY)); } /** @@ -342,7 +342,7 @@ abstract public class TimeZone implements Serializable, Cloneable { * @since 1.2 */ public final String getDisplayName(boolean daylight, int style) { - return getDisplayName(daylight, style, Locale.getDefault()); + return getDisplayName(daylight, style, Locale.getDefault(Locale.Category.DISPLAY)); } /** diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java index f250a5e9835..122ce86737e 100644 --- a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java @@ -40,16 +40,23 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.concurrent.locks.Condition; +import java.util.concurrent.AbstractExecutorService; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RunnableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; /** * An {@link ExecutorService} for running {@link ForkJoinTask}s. * A {@code ForkJoinPool} provides the entry point for submissions - * from non-{@code ForkJoinTask}s, as well as management and + * from non-{@code ForkJoinTask} clients, as well as management and * monitoring operations. * *

    A {@code ForkJoinPool} differs from other kinds of {@link @@ -58,29 +65,19 @@ import java.util.concurrent.atomic.AtomicLong; * execute subtasks created by other active tasks (eventually blocking * waiting for work if none exist). This enables efficient processing * when most tasks spawn other subtasks (as do most {@code - * ForkJoinTask}s). A {@code ForkJoinPool} may also be used for mixed - * execution of some plain {@code Runnable}- or {@code Callable}- - * based activities along with {@code ForkJoinTask}s. When setting - * {@linkplain #setAsyncMode async mode}, a {@code ForkJoinPool} may - * also be appropriate for use with fine-grained tasks of any form - * that are never joined. Otherwise, other {@code ExecutorService} - * implementations are typically more appropriate choices. + * ForkJoinTask}s). When setting asyncMode to true in + * constructors, {@code ForkJoinPool}s may also be appropriate for use + * with event-style tasks that are never joined. * *

    A {@code ForkJoinPool} is constructed with a given target * parallelism level; by default, equal to the number of available - * processors. Unless configured otherwise via {@link - * #setMaintainsParallelism}, the pool attempts to maintain this - * number of active (or available) threads by dynamically adding, - * suspending, or resuming internal worker threads, even if some tasks - * are stalled waiting to join others. However, no such adjustments - * are performed in the face of blocked IO or other unmanaged - * synchronization. The nested {@link ManagedBlocker} interface - * enables extension of the kinds of synchronization accommodated. - * The target parallelism level may also be changed dynamically - * ({@link #setParallelism}). The total number of threads may be - * limited using method {@link #setMaximumPoolSize}, in which case it - * may become possible for the activities of a pool to stall due to - * the lack of available threads to process new tasks. + * processors. The pool attempts to maintain enough active (or + * available) threads by dynamically adding, suspending, or resuming + * internal worker threads, even if some tasks are stalled waiting to + * join others. However, no such adjustments are guaranteed in the + * face of blocked IO or other unmanaged synchronization. The nested + * {@link ManagedBlocker} interface enables extension of the kinds of + * synchronization accommodated. * *

    In addition to execution and lifecycle control methods, this * class provides status check methods (for example @@ -89,6 +86,40 @@ import java.util.concurrent.atomic.AtomicLong; * {@link #toString} returns indications of pool state in a * convenient form for informal monitoring. * + *

    As is the case with other ExecutorServices, there are three + * main task execution methods summarized in the following + * table. These are designed to be used by clients not already engaged + * in fork/join computations in the current pool. The main forms of + * these methods accept instances of {@code ForkJoinTask}, but + * overloaded forms also allow mixed execution of plain {@code + * Runnable}- or {@code Callable}- based activities as well. However, + * tasks that are already executing in a pool should normally + * NOT use these pool execution methods, but instead use the + * within-computation forms listed in the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Call from non-fork/join clients Call from within fork/join computations
    Arrange async execution {@link #execute(ForkJoinTask)} {@link ForkJoinTask#fork}
    Await and obtain result {@link #invoke(ForkJoinTask)} {@link ForkJoinTask#invoke}
    Arrange exec and obtain Future {@link #submit(ForkJoinTask)} {@link ForkJoinTask#fork} (ForkJoinTasks are Futures)
    + * *

    Sample Usage. Normally a single {@code ForkJoinPool} is * used for all parallel task execution in a program or subsystem. * Otherwise, use would not usually outweigh the construction and @@ -113,7 +144,8 @@ import java.util.concurrent.atomic.AtomicLong; * {@code IllegalArgumentException}. * *

    This implementation rejects submitted tasks (that is, by throwing - * {@link RejectedExecutionException}) only when the pool is shut down. + * {@link RejectedExecutionException}) only when the pool is shut down + * or internal resources have been exhausted. * * @since 1.7 * @author Doug Lea @@ -121,16 +153,247 @@ import java.util.concurrent.atomic.AtomicLong; public class ForkJoinPool extends AbstractExecutorService { /* - * See the extended comments interspersed below for design, - * rationale, and walkthroughs. + * Implementation Overview + * + * This class provides the central bookkeeping and control for a + * set of worker threads: Submissions from non-FJ threads enter + * into a submission queue. Workers take these tasks and typically + * split them into subtasks that may be stolen by other workers. + * The main work-stealing mechanics implemented in class + * ForkJoinWorkerThread give first priority to processing tasks + * from their own queues (LIFO or FIFO, depending on mode), then + * to randomized FIFO steals of tasks in other worker queues, and + * lastly to new submissions. These mechanics do not consider + * affinities, loads, cache localities, etc, so rarely provide the + * best possible performance on a given machine, but portably + * provide good throughput by averaging over these factors. + * (Further, even if we did try to use such information, we do not + * usually have a basis for exploiting it. For example, some sets + * of tasks profit from cache affinities, but others are harmed by + * cache pollution effects.) + * + * Beyond work-stealing support and essential bookkeeping, the + * main responsibility of this framework is to take actions when + * one worker is waiting to join a task stolen (or always held by) + * another. Because we are multiplexing many tasks on to a pool + * of workers, we can't just let them block (as in Thread.join). + * We also cannot just reassign the joiner's run-time stack with + * another and replace it later, which would be a form of + * "continuation", that even if possible is not necessarily a good + * idea. Given that the creation costs of most threads on most + * systems mainly surrounds setting up runtime stacks, thread + * creation and switching is usually not much more expensive than + * stack creation and switching, and is more flexible). Instead we + * combine two tactics: + * + * Helping: Arranging for the joiner to execute some task that it + * would be running if the steal had not occurred. Method + * ForkJoinWorkerThread.helpJoinTask tracks joining->stealing + * links to try to find such a task. + * + * Compensating: Unless there are already enough live threads, + * method helpMaintainParallelism() may create or + * re-activate a spare thread to compensate for blocked + * joiners until they unblock. + * + * It is impossible to keep exactly the target (parallelism) + * number of threads running at any given time. Determining + * existence of conservatively safe helping targets, the + * availability of already-created spares, and the apparent need + * to create new spares are all racy and require heuristic + * guidance, so we rely on multiple retries of each. Compensation + * occurs in slow-motion. It is triggered only upon timeouts of + * Object.wait used for joins. This reduces poor decisions that + * would otherwise be made when threads are waiting for others + * that are stalled because of unrelated activities such as + * garbage collection. + * + * The ManagedBlocker extension API can't use helping so relies + * only on compensation in method awaitBlocker. + * + * The main throughput advantages of work-stealing stem from + * decentralized control -- workers mostly steal tasks from each + * other. We do not want to negate this by creating bottlenecks + * implementing other management responsibilities. So we use a + * collection of techniques that avoid, reduce, or cope well with + * contention. These entail several instances of bit-packing into + * CASable fields to maintain only the minimally required + * atomicity. To enable such packing, we restrict maximum + * parallelism to (1<<15)-1 (enabling twice this (to accommodate + * unbalanced increments and decrements) to fit into a 16 bit + * field, which is far in excess of normal operating range. Even + * though updates to some of these bookkeeping fields do sometimes + * contend with each other, they don't normally cache-contend with + * updates to others enough to warrant memory padding or + * isolation. So they are all held as fields of ForkJoinPool + * objects. The main capabilities are as follows: + * + * 1. Creating and removing workers. Workers are recorded in the + * "workers" array. This is an array as opposed to some other data + * structure to support index-based random steals by workers. + * Updates to the array recording new workers and unrecording + * terminated ones are protected from each other by a lock + * (workerLock) but the array is otherwise concurrently readable, + * and accessed directly by workers. To simplify index-based + * operations, the array size is always a power of two, and all + * readers must tolerate null slots. Currently, all worker thread + * creation is on-demand, triggered by task submissions, + * replacement of terminated workers, and/or compensation for + * blocked workers. However, all other support code is set up to + * work with other policies. + * + * To ensure that we do not hold on to worker references that + * would prevent GC, ALL accesses to workers are via indices into + * the workers array (which is one source of some of the unusual + * code constructions here). In essence, the workers array serves + * as a WeakReference mechanism. Thus for example the event queue + * stores worker indices, not worker references. Access to the + * workers in associated methods (for example releaseEventWaiters) + * must both index-check and null-check the IDs. All such accesses + * ignore bad IDs by returning out early from what they are doing, + * since this can only be associated with shutdown, in which case + * it is OK to give up. On termination, we just clobber these + * data structures without trying to use them. + * + * 2. Bookkeeping for dynamically adding and removing workers. We + * aim to approximately maintain the given level of parallelism. + * When some workers are known to be blocked (on joins or via + * ManagedBlocker), we may create or resume others to take their + * place until they unblock (see below). Implementing this + * requires counts of the number of "running" threads (i.e., those + * that are neither blocked nor artificially suspended) as well as + * the total number. These two values are packed into one field, + * "workerCounts" because we need accurate snapshots when deciding + * to create, resume or suspend. Note however that the + * correspondence of these counts to reality is not guaranteed. In + * particular updates for unblocked threads may lag until they + * actually wake up. + * + * 3. Maintaining global run state. The run state of the pool + * consists of a runLevel (SHUTDOWN, TERMINATING, etc) similar to + * those in other Executor implementations, as well as a count of + * "active" workers -- those that are, or soon will be, or + * recently were executing tasks. The runLevel and active count + * are packed together in order to correctly trigger shutdown and + * termination. Without care, active counts can be subject to very + * high contention. We substantially reduce this contention by + * relaxing update rules. A worker must claim active status + * prospectively, by activating if it sees that a submitted or + * stealable task exists (it may find after activating that the + * task no longer exists). It stays active while processing this + * task (if it exists) and any other local subtasks it produces, + * until it cannot find any other tasks. It then tries + * inactivating (see method preStep), but upon update contention + * instead scans for more tasks, later retrying inactivation if it + * doesn't find any. + * + * 4. Managing idle workers waiting for tasks. We cannot let + * workers spin indefinitely scanning for tasks when none are + * available. On the other hand, we must quickly prod them into + * action when new tasks are submitted or generated. We + * park/unpark these idle workers using an event-count scheme. + * Field eventCount is incremented upon events that may enable + * workers that previously could not find a task to now find one: + * Submission of a new task to the pool, or another worker pushing + * a task onto a previously empty queue. (We also use this + * mechanism for configuration and termination actions that + * require wakeups of idle workers). Each worker maintains its + * last known event count, and blocks when a scan for work did not + * find a task AND its lastEventCount matches the current + * eventCount. Waiting idle workers are recorded in a variant of + * Treiber stack headed by field eventWaiters which, when nonzero, + * encodes the thread index and count awaited for by the worker + * thread most recently calling eventSync. This thread in turn has + * a record (field nextEventWaiter) for the next waiting worker. + * In addition to allowing simpler decisions about need for + * wakeup, the event count bits in eventWaiters serve the role of + * tags to avoid ABA errors in Treiber stacks. Upon any wakeup, + * released threads also try to release at most two others. The + * net effect is a tree-like diffusion of signals, where released + * threads (and possibly others) help with unparks. To further + * reduce contention effects a bit, failed CASes to increment + * field eventCount are tolerated without retries in signalWork. + * Conceptually they are merged into the same event, which is OK + * when their only purpose is to enable workers to scan for work. + * + * 5. Managing suspension of extra workers. When a worker notices + * (usually upon timeout of a wait()) that there are too few + * running threads, we may create a new thread to maintain + * parallelism level, or at least avoid starvation. Usually, extra + * threads are needed for only very short periods, yet join + * dependencies are such that we sometimes need them in + * bursts. Rather than create new threads each time this happens, + * we suspend no-longer-needed extra ones as "spares". For most + * purposes, we don't distinguish "extra" spare threads from + * normal "core" threads: On each call to preStep (the only point + * at which we can do this) a worker checks to see if there are + * now too many running workers, and if so, suspends itself. + * Method helpMaintainParallelism looks for suspended threads to + * resume before considering creating a new replacement. The + * spares themselves are encoded on another variant of a Treiber + * Stack, headed at field "spareWaiters". Note that the use of + * spares is intrinsically racy. One thread may become a spare at + * about the same time as another is needlessly being created. We + * counteract this and related slop in part by requiring resumed + * spares to immediately recheck (in preStep) to see whether they + * should re-suspend. + * + * 6. Killing off unneeded workers. A timeout mechanism is used to + * shed unused workers: The oldest (first) event queue waiter uses + * a timed rather than hard wait. When this wait times out without + * a normal wakeup, it tries to shutdown any one (for convenience + * the newest) other spare or event waiter via + * tryShutdownUnusedWorker. This eventually reduces the number of + * worker threads to a minimum of one after a long enough period + * without use. + * + * 7. Deciding when to create new workers. The main dynamic + * control in this class is deciding when to create extra threads + * in method helpMaintainParallelism. We would like to keep + * exactly #parallelism threads running, which is an impossible + * task. We always need to create one when the number of running + * threads would become zero and all workers are busy. Beyond + * this, we must rely on heuristics that work well in the + * presence of transient phenomena such as GC stalls, dynamic + * compilation, and wake-up lags. These transients are extremely + * common -- we are normally trying to fully saturate the CPUs on + * a machine, so almost any activity other than running tasks + * impedes accuracy. Our main defense is to allow parallelism to + * lapse for a while during joins, and use a timeout to see if, + * after the resulting settling, there is still a need for + * additional workers. This also better copes with the fact that + * some of the methods in this class tend to never become compiled + * (but are interpreted), so some components of the entire set of + * controls might execute 100 times faster than others. And + * similarly for cases where the apparent lack of work is just due + * to GC stalls and other transient system activity. + * + * Beware that there is a lot of representation-level coupling + * among classes ForkJoinPool, ForkJoinWorkerThread, and + * ForkJoinTask. For example, direct access to "workers" array by + * workers, and direct access to ForkJoinTask.status by both + * ForkJoinPool and ForkJoinWorkerThread. There is little point + * trying to reduce this, since any associated future changes in + * representations will need to be accompanied by algorithmic + * changes anyway. + * + * Style notes: There are lots of inline assignments (of form + * "while ((local = field) != 0)") which are usually the simplest + * way to ensure the required read orderings (which are sometimes + * critical). Also several occurrences of the unusual "do {} + * while (!cas...)" which is the simplest way to force an update of + * a CAS'ed variable. There are also other coding oddities that + * help some methods perform reasonably even when interpreted (not + * compiled), at the expense of some messy constructions that + * reduce byte code counts. + * + * The order of declarations in this file is: (1) statics (2) + * fields (along with constants used when unpacking some of them) + * (3) internal control methods (4) callbacks and other support + * for ForkJoinTask and ForkJoinWorkerThread classes, (5) exported + * methods (plus a few little helpers). */ - /** Mask for packing and unpacking shorts */ - private static final int shortMask = 0xffff; - - /** Max pool size -- must be a power of two minus 1 */ - private static final int MAX_THREADS = 0x7FFF; - /** * Factory for creating new {@link ForkJoinWorkerThread}s. * A {@code ForkJoinWorkerThreadFactory} must be defined and used @@ -151,14 +414,10 @@ public class ForkJoinPool extends AbstractExecutorService { * Default ForkJoinWorkerThreadFactory implementation; creates a * new ForkJoinWorkerThread. */ - static class DefaultForkJoinWorkerThreadFactory + static class DefaultForkJoinWorkerThreadFactory implements ForkJoinWorkerThreadFactory { public ForkJoinWorkerThread newThread(ForkJoinPool pool) { - try { - return new ForkJoinWorkerThread(pool); - } catch (OutOfMemoryError oom) { - return null; - } + return new ForkJoinWorkerThread(pool); } } @@ -194,208 +453,777 @@ public class ForkJoinPool extends AbstractExecutorService { new AtomicInteger(); /** - * Array holding all worker threads in the pool. Initialized upon - * first use. Array size must be a power of two. Updates and - * replacements are protected by workerLock, but it is always kept - * in a consistent enough state to be randomly accessed without - * locking by workers performing work-stealing. + * The time to block in a join (see awaitJoin) before checking if + * a new worker should be (re)started to maintain parallelism + * level. The value should be short enough to maintain global + * responsiveness and progress but long enough to avoid + * counterproductive firings during GC stalls or unrelated system + * activity, and to not bog down systems with continual re-firings + * on GCs or legitimately long waits. + */ + private static final long JOIN_TIMEOUT_MILLIS = 250L; // 4 per second + + /** + * The wakeup interval (in nanoseconds) for the oldest worker + * waiting for an event to invoke tryShutdownUnusedWorker to + * shrink the number of workers. The exact value does not matter + * too much. It must be short enough to release resources during + * sustained periods of idleness, but not so short that threads + * are continually re-created. + */ + private static final long SHRINK_RATE_NANOS = + 30L * 1000L * 1000L * 1000L; // 2 per minute + + /** + * Absolute bound for parallelism level. Twice this number plus + * one (i.e., 0xfff) must fit into a 16bit field to enable + * word-packing for some counts and indices. + */ + private static final int MAX_WORKERS = 0x7fff; + + /** + * Array holding all worker threads in the pool. Array size must + * be a power of two. Updates and replacements are protected by + * workerLock, but the array is always kept in a consistent enough + * state to be randomly accessed without locking by workers + * performing work-stealing, as well as other traversal-based + * methods in this class. All readers must tolerate that some + * array slots may be null. */ volatile ForkJoinWorkerThread[] workers; - /** - * Lock protecting access to workers. - */ - private final ReentrantLock workerLock; - - /** - * Condition for awaitTermination. - */ - private final Condition termination; - - /** - * The uncaught exception handler used when any worker - * abruptly terminates - */ - private Thread.UncaughtExceptionHandler ueh; - - /** - * Creation factory for worker threads. - */ - private final ForkJoinWorkerThreadFactory factory; - - /** - * Head of stack of threads that were created to maintain - * parallelism when other threads blocked, but have since - * suspended when the parallelism level rose. - */ - private volatile WaitQueueNode spareStack; - - /** - * Sum of per-thread steal counts, updated only when threads are - * idle or terminating. - */ - private final AtomicLong stealCount; - /** * Queue for external submissions. */ private final LinkedTransferQueue> submissionQueue; /** - * Head of Treiber stack for barrier sync. See below for explanation. + * Lock protecting updates to workers array. */ - private volatile WaitQueueNode syncStack; + private final ReentrantLock workerLock; /** - * The count for event barrier + * Latch released upon termination. */ - private volatile long eventCount; + private final Phaser termination; + + /** + * Creation factory for worker threads. + */ + private final ForkJoinWorkerThreadFactory factory; + + /** + * Sum of per-thread steal counts, updated only when threads are + * idle or terminating. + */ + private volatile long stealCount; + + /** + * Encoded record of top of Treiber stack of threads waiting for + * events. The top 32 bits contain the count being waited for. The + * bottom 16 bits contains one plus the pool index of waiting + * worker thread. (Bits 16-31 are unused.) + */ + private volatile long eventWaiters; + + private static final int EVENT_COUNT_SHIFT = 32; + private static final long WAITER_ID_MASK = (1L << 16) - 1L; + + /** + * A counter for events that may wake up worker threads: + * - Submission of a new task to the pool + * - A worker pushing a task on an empty queue + * - termination + */ + private volatile int eventCount; + + /** + * Encoded record of top of Treiber stack of spare threads waiting + * for resumption. The top 16 bits contain an arbitrary count to + * avoid ABA effects. The bottom 16bits contains one plus the pool + * index of waiting worker thread. + */ + private volatile int spareWaiters; + + private static final int SPARE_COUNT_SHIFT = 16; + private static final int SPARE_ID_MASK = (1 << 16) - 1; + + /** + * Lifecycle control. The low word contains the number of workers + * that are (probably) executing tasks. This value is atomically + * incremented before a worker gets a task to run, and decremented + * when a worker has no tasks and cannot find any. Bits 16-18 + * contain runLevel value. When all are zero, the pool is + * running. Level transitions are monotonic (running -> shutdown + * -> terminating -> terminated) so each transition adds a bit. + * These are bundled together to ensure consistent read for + * termination checks (i.e., that runLevel is at least SHUTDOWN + * and active threads is zero). + * + * Notes: Most direct CASes are dependent on these bitfield + * positions. Also, this field is non-private to enable direct + * performance-sensitive CASes in ForkJoinWorkerThread. + */ + volatile int runState; + + // Note: The order among run level values matters. + private static final int RUNLEVEL_SHIFT = 16; + private static final int SHUTDOWN = 1 << RUNLEVEL_SHIFT; + private static final int TERMINATING = 1 << (RUNLEVEL_SHIFT + 1); + private static final int TERMINATED = 1 << (RUNLEVEL_SHIFT + 2); + private static final int ACTIVE_COUNT_MASK = (1 << RUNLEVEL_SHIFT) - 1; + + /** + * Holds number of total (i.e., created and not yet terminated) + * and running (i.e., not blocked on joins or other managed sync) + * threads, packed together to ensure consistent snapshot when + * making decisions about creating and suspending spare + * threads. Updated only by CAS. Note that adding a new worker + * requires incrementing both counts, since workers start off in + * running state. + */ + private volatile int workerCounts; + + private static final int TOTAL_COUNT_SHIFT = 16; + private static final int RUNNING_COUNT_MASK = (1 << TOTAL_COUNT_SHIFT) - 1; + private static final int ONE_RUNNING = 1; + private static final int ONE_TOTAL = 1 << TOTAL_COUNT_SHIFT; + + /** + * The target parallelism level. + * Accessed directly by ForkJoinWorkerThreads. + */ + final int parallelism; + + /** + * True if use local fifo, not default lifo, for local polling + * Read by, and replicated by ForkJoinWorkerThreads + */ + final boolean locallyFifo; + + /** + * The uncaught exception handler used when any worker abruptly + * terminates. + */ + private final Thread.UncaughtExceptionHandler ueh; /** * Pool number, just for assigning useful names to worker threads */ private final int poolNumber; - /** - * The maximum allowed pool size - */ - private volatile int maxPoolSize; + // Utilities for CASing fields. Note that most of these + // are usually manually inlined by callers /** - * The desired parallelism level, updated only under workerLock. + * Increments running count part of workerCounts */ - private volatile int parallelism; - - /** - * True if use local fifo, not default lifo, for local polling - */ - private volatile boolean locallyFifo; - - /** - * Holds number of total (i.e., created and not yet terminated) - * and running (i.e., not blocked on joins or other managed sync) - * threads, packed into one int to ensure consistent snapshot when - * making decisions about creating and suspending spare - * threads. Updated only by CAS. Note: CASes in - * updateRunningCount and preJoin assume that running active count - * is in low word, so need to be modified if this changes. - */ - private volatile int workerCounts; - - private static int totalCountOf(int s) { return s >>> 16; } - private static int runningCountOf(int s) { return s & shortMask; } - private static int workerCountsFor(int t, int r) { return (t << 16) + r; } - - /** - * Adds delta (which may be negative) to running count. This must - * be called before (with negative arg) and after (with positive) - * any managed synchronization (i.e., mainly, joins). - * - * @param delta the number to add - */ - final void updateRunningCount(int delta) { - int s; - do {} while (!casWorkerCounts(s = workerCounts, s + delta)); + final void incrementRunningCount() { + int c; + do {} while (!UNSAFE.compareAndSwapInt(this, workerCountsOffset, + c = workerCounts, + c + ONE_RUNNING)); } /** - * Adds delta (which may be negative) to both total and running - * count. This must be called upon creation and termination of - * worker threads. - * - * @param delta the number to add + * Tries to decrement running count unless already zero */ - private void updateWorkerCount(int delta) { - int d = delta + (delta << 16); // add to both lo and hi parts - int s; - do {} while (!casWorkerCounts(s = workerCounts, s + d)); - } - - /** - * Lifecycle control. High word contains runState, low word - * contains the number of workers that are (probably) executing - * tasks. This value is atomically incremented before a worker - * gets a task to run, and decremented when worker has no tasks - * and cannot find any. These two fields are bundled together to - * support correct termination triggering. Note: activeCount - * CAS'es cheat by assuming active count is in low word, so need - * to be modified if this changes - */ - private volatile int runControl; - - // RunState values. Order among values matters - private static final int RUNNING = 0; - private static final int SHUTDOWN = 1; - private static final int TERMINATING = 2; - private static final int TERMINATED = 3; - - private static int runStateOf(int c) { return c >>> 16; } - private static int activeCountOf(int c) { return c & shortMask; } - private static int runControlFor(int r, int a) { return (r << 16) + a; } - - /** - * Tries incrementing active count; fails on contention. - * Called by workers before/during executing tasks. - * - * @return true on success - */ - final boolean tryIncrementActiveCount() { - int c = runControl; - return casRunControl(c, c+1); - } - - /** - * Tries decrementing active count; fails on contention. - * Possibly triggers termination on success. - * Called by workers when they can't find tasks. - * - * @return true on success - */ - final boolean tryDecrementActiveCount() { - int c = runControl; - int nextc = c - 1; - if (!casRunControl(c, nextc)) + final boolean tryDecrementRunningCount() { + int wc = workerCounts; + if ((wc & RUNNING_COUNT_MASK) == 0) return false; - if (canTerminateOnShutdown(nextc)) - terminateOnShutdown(); - return true; + return UNSAFE.compareAndSwapInt(this, workerCountsOffset, + wc, wc - ONE_RUNNING); } /** - * Returns {@code true} if argument represents zero active count - * and nonzero runstate, which is the triggering condition for - * terminating on shutdown. + * Forces decrement of encoded workerCounts, awaiting nonzero if + * (rarely) necessary when other count updates lag. + * + * @param dr -- either zero or ONE_RUNNING + * @param dt -- either zero or ONE_TOTAL */ - private static boolean canTerminateOnShutdown(int c) { - // i.e. least bit is nonzero runState bit - return ((c & -c) >>> 16) != 0; - } - - /** - * Transition run state to at least the given state. Return true - * if not already at least given state. - */ - private boolean transitionRunStateTo(int state) { + private void decrementWorkerCounts(int dr, int dt) { for (;;) { - int c = runControl; - if (runStateOf(c) >= state) - return false; - if (casRunControl(c, runControlFor(state, activeCountOf(c)))) - return true; + int wc = workerCounts; + if ((wc & RUNNING_COUNT_MASK) - dr < 0 || + (wc >>> TOTAL_COUNT_SHIFT) - dt < 0) { + if ((runState & TERMINATED) != 0) + return; // lagging termination on a backout + Thread.yield(); + } + if (UNSAFE.compareAndSwapInt(this, workerCountsOffset, + wc, wc - (dr + dt))) + return; } } /** - * Controls whether to add spares to maintain parallelism + * Tries decrementing active count; fails on contention. + * Called when workers cannot find tasks to run. */ - private volatile boolean maintainsParallelism; + final boolean tryDecrementActiveCount() { + int c; + return UNSAFE.compareAndSwapInt(this, runStateOffset, + c = runState, c - 1); + } + + /** + * Advances to at least the given level. Returns true if not + * already in at least the given level. + */ + private boolean advanceRunLevel(int level) { + for (;;) { + int s = runState; + if ((s & level) != 0) + return false; + if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, s | level)) + return true; + } + } + + // workers array maintenance + + /** + * Records and returns a workers array index for new worker. + */ + private int recordWorker(ForkJoinWorkerThread w) { + // Try using slot totalCount-1. If not available, scan and/or resize + int k = (workerCounts >>> TOTAL_COUNT_SHIFT) - 1; + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ForkJoinWorkerThread[] ws = workers; + int n = ws.length; + if (k < 0 || k >= n || ws[k] != null) { + for (k = 0; k < n && ws[k] != null; ++k) + ; + if (k == n) + ws = Arrays.copyOf(ws, n << 1); + } + ws[k] = w; + workers = ws; // volatile array write ensures slot visibility + } finally { + lock.unlock(); + } + return k; + } + + /** + * Nulls out record of worker in workers array. + */ + private void forgetWorker(ForkJoinWorkerThread w) { + int idx = w.poolIndex; + // Locking helps method recordWorker avoid unnecessary expansion + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ForkJoinWorkerThread[] ws = workers; + if (idx >= 0 && idx < ws.length && ws[idx] == w) // verify + ws[idx] = null; + } finally { + lock.unlock(); + } + } + + /** + * Final callback from terminating worker. Removes record of + * worker from array, and adjusts counts. If pool is shutting + * down, tries to complete termination. + * + * @param w the worker + */ + final void workerTerminated(ForkJoinWorkerThread w) { + forgetWorker(w); + decrementWorkerCounts(w.isTrimmed()? 0 : ONE_RUNNING, ONE_TOTAL); + while (w.stealCount != 0) // collect final count + tryAccumulateStealCount(w); + tryTerminate(false); + } + + // Waiting for and signalling events + + /** + * Releases workers blocked on a count not equal to current count. + * Normally called after precheck that eventWaiters isn't zero to + * avoid wasted array checks. Gives up upon a change in count or + * upon releasing two workers, letting others take over. + */ + private void releaseEventWaiters() { + ForkJoinWorkerThread[] ws = workers; + int n = ws.length; + long h = eventWaiters; + int ec = eventCount; + boolean releasedOne = false; + ForkJoinWorkerThread w; int id; + while ((id = ((int)(h & WAITER_ID_MASK)) - 1) >= 0 && + (int)(h >>> EVENT_COUNT_SHIFT) != ec && + id < n && (w = ws[id]) != null) { + if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset, + h, w.nextWaiter)) { + LockSupport.unpark(w); + if (releasedOne) // exit on second release + break; + releasedOne = true; + } + if (eventCount != ec) + break; + h = eventWaiters; + } + } + + /** + * Tries to advance eventCount and releases waiters. Called only + * from workers. + */ + final void signalWork() { + int c; // try to increment event count -- CAS failure OK + UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1); + if (eventWaiters != 0L) + releaseEventWaiters(); + } + + /** + * Adds the given worker to event queue and blocks until + * terminating or event count advances from the given value + * + * @param w the calling worker thread + * @param ec the count + */ + private void eventSync(ForkJoinWorkerThread w, int ec) { + long nh = (((long)ec) << EVENT_COUNT_SHIFT) | ((long)(w.poolIndex+1)); + long h; + while ((runState < SHUTDOWN || !tryTerminate(false)) && + (((int)((h = eventWaiters) & WAITER_ID_MASK)) == 0 || + (int)(h >>> EVENT_COUNT_SHIFT) == ec) && + eventCount == ec) { + if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset, + w.nextWaiter = h, nh)) { + awaitEvent(w, ec); + break; + } + } + } + + /** + * Blocks the given worker (that has already been entered as an + * event waiter) until terminating or event count advances from + * the given value. The oldest (first) waiter uses a timed wait to + * occasionally one-by-one shrink the number of workers (to a + * minimum of one) if the pool has not been used for extended + * periods. + * + * @param w the calling worker thread + * @param ec the count + */ + private void awaitEvent(ForkJoinWorkerThread w, int ec) { + while (eventCount == ec) { + if (tryAccumulateStealCount(w)) { // transfer while idle + boolean untimed = (w.nextWaiter != 0L || + (workerCounts & RUNNING_COUNT_MASK) <= 1); + long startTime = untimed? 0 : System.nanoTime(); + Thread.interrupted(); // clear/ignore interrupt + if (eventCount != ec || w.runState != 0 || + runState >= TERMINATING) // recheck after clear + break; + if (untimed) + LockSupport.park(w); + else { + LockSupport.parkNanos(w, SHRINK_RATE_NANOS); + if (eventCount != ec || w.runState != 0 || + runState >= TERMINATING) + break; + if (System.nanoTime() - startTime >= SHRINK_RATE_NANOS) + tryShutdownUnusedWorker(ec); + } + } + } + } + + // Maintaining parallelism + + /** + * Pushes worker onto the spare stack. + */ + final void pushSpare(ForkJoinWorkerThread w) { + int ns = (++w.spareCount << SPARE_COUNT_SHIFT) | (w.poolIndex + 1); + do {} while (!UNSAFE.compareAndSwapInt(this, spareWaitersOffset, + w.nextSpare = spareWaiters,ns)); + } + + /** + * Tries (once) to resume a spare if the number of running + * threads is less than target. + */ + private void tryResumeSpare() { + int sw, id; + ForkJoinWorkerThread[] ws = workers; + int n = ws.length; + ForkJoinWorkerThread w; + if ((sw = spareWaiters) != 0 && + (id = (sw & SPARE_ID_MASK) - 1) >= 0 && + id < n && (w = ws[id]) != null && + (workerCounts & RUNNING_COUNT_MASK) < parallelism && + spareWaiters == sw && + UNSAFE.compareAndSwapInt(this, spareWaitersOffset, + sw, w.nextSpare)) { + int c; // increment running count before resume + do {} while (!UNSAFE.compareAndSwapInt + (this, workerCountsOffset, + c = workerCounts, c + ONE_RUNNING)); + if (w.tryUnsuspend()) + LockSupport.unpark(w); + else // back out if w was shutdown + decrementWorkerCounts(ONE_RUNNING, 0); + } + } + + /** + * Tries to increase the number of running workers if below target + * parallelism: If a spare exists tries to resume it via + * tryResumeSpare. Otherwise, if not enough total workers or all + * existing workers are busy, adds a new worker. In all cases also + * helps wake up releasable workers waiting for work. + */ + private void helpMaintainParallelism() { + int pc = parallelism; + int wc, rs, tc; + while (((wc = workerCounts) & RUNNING_COUNT_MASK) < pc && + (rs = runState) < TERMINATING) { + if (spareWaiters != 0) + tryResumeSpare(); + else if ((tc = wc >>> TOTAL_COUNT_SHIFT) >= MAX_WORKERS || + (tc >= pc && (rs & ACTIVE_COUNT_MASK) != tc)) + break; // enough total + else if (runState == rs && workerCounts == wc && + UNSAFE.compareAndSwapInt(this, workerCountsOffset, wc, + wc + (ONE_RUNNING|ONE_TOTAL))) { + ForkJoinWorkerThread w = null; + try { + w = factory.newThread(this); + } finally { // adjust on null or exceptional factory return + if (w == null) { + decrementWorkerCounts(ONE_RUNNING, ONE_TOTAL); + tryTerminate(false); // handle failure during shutdown + } + } + if (w == null) + break; + w.start(recordWorker(w), ueh); + if ((workerCounts >>> TOTAL_COUNT_SHIFT) >= pc) { + int c; // advance event count + UNSAFE.compareAndSwapInt(this, eventCountOffset, + c = eventCount, c+1); + break; // add at most one unless total below target + } + } + } + if (eventWaiters != 0L) + releaseEventWaiters(); + } + + /** + * Callback from the oldest waiter in awaitEvent waking up after a + * period of non-use. If all workers are idle, tries (once) to + * shutdown an event waiter or a spare, if one exists. Note that + * we don't need CAS or locks here because the method is called + * only from one thread occasionally waking (and even misfires are + * OK). Note that until the shutdown worker fully terminates, + * workerCounts will overestimate total count, which is tolerable. + * + * @param ec the event count waited on by caller (to abort + * attempt if count has since changed). + */ + private void tryShutdownUnusedWorker(int ec) { + if (runState == 0 && eventCount == ec) { // only trigger if all idle + ForkJoinWorkerThread[] ws = workers; + int n = ws.length; + ForkJoinWorkerThread w = null; + boolean shutdown = false; + int sw; + long h; + if ((sw = spareWaiters) != 0) { // prefer killing spares + int id = (sw & SPARE_ID_MASK) - 1; + if (id >= 0 && id < n && (w = ws[id]) != null && + UNSAFE.compareAndSwapInt(this, spareWaitersOffset, + sw, w.nextSpare)) + shutdown = true; + } + else if ((h = eventWaiters) != 0L) { + long nh; + int id = ((int)(h & WAITER_ID_MASK)) - 1; + if (id >= 0 && id < n && (w = ws[id]) != null && + (nh = w.nextWaiter) != 0L && // keep at least one worker + UNSAFE.compareAndSwapLong(this, eventWaitersOffset, h, nh)) + shutdown = true; + } + if (w != null && shutdown) { + w.shutdown(); + LockSupport.unpark(w); + } + } + releaseEventWaiters(); // in case of interference + } + + /** + * Callback from workers invoked upon each top-level action (i.e., + * stealing a task or taking a submission and running it). + * Performs one or more of the following: + * + * 1. If the worker is active and either did not run a task + * or there are too many workers, try to set its active status + * to inactive and update activeCount. On contention, we may + * try again in this or a subsequent call. + * + * 2. If not enough total workers, help create some. + * + * 3. If there are too many running workers, suspend this worker + * (first forcing inactive if necessary). If it is not needed, + * it may be shutdown while suspended (via + * tryShutdownUnusedWorker). Otherwise, upon resume it + * rechecks running thread count and need for event sync. + * + * 4. If worker did not run a task, await the next task event via + * eventSync if necessary (first forcing inactivation), upon + * which the worker may be shutdown via + * tryShutdownUnusedWorker. Otherwise, help release any + * existing event waiters that are now releasable, + * + * @param w the worker + * @param ran true if worker ran a task since last call to this method + */ + final void preStep(ForkJoinWorkerThread w, boolean ran) { + int wec = w.lastEventCount; + boolean active = w.active; + boolean inactivate = false; + int pc = parallelism; + int rs; + while (w.runState == 0 && (rs = runState) < TERMINATING) { + if ((inactivate || (active && (rs & ACTIVE_COUNT_MASK) >= pc)) && + UNSAFE.compareAndSwapInt(this, runStateOffset, rs, rs - 1)) + inactivate = active = w.active = false; + int wc = workerCounts; + if ((wc & RUNNING_COUNT_MASK) > pc) { + if (!(inactivate |= active) && // must inactivate to suspend + workerCounts == wc && // try to suspend as spare + UNSAFE.compareAndSwapInt(this, workerCountsOffset, + wc, wc - ONE_RUNNING)) + w.suspendAsSpare(); + } + else if ((wc >>> TOTAL_COUNT_SHIFT) < pc) + helpMaintainParallelism(); // not enough workers + else if (!ran) { + long h = eventWaiters; + int ec = eventCount; + if (h != 0L && (int)(h >>> EVENT_COUNT_SHIFT) != ec) + releaseEventWaiters(); // release others before waiting + else if (ec != wec) { + w.lastEventCount = ec; // no need to wait + break; + } + else if (!(inactivate |= active)) + eventSync(w, wec); // must inactivate before sync + } + else + break; + } + } + + /** + * Helps and/or blocks awaiting join of the given task. + * See above for explanation. + * + * @param joinMe the task to join + * @param worker the current worker thread + */ + final void awaitJoin(ForkJoinTask joinMe, ForkJoinWorkerThread worker) { + int retries = 2 + (parallelism >> 2); // #helpJoins before blocking + while (joinMe.status >= 0) { + int wc; + worker.helpJoinTask(joinMe); + if (joinMe.status < 0) + break; + else if (retries > 0) + --retries; + else if (((wc = workerCounts) & RUNNING_COUNT_MASK) != 0 && + UNSAFE.compareAndSwapInt(this, workerCountsOffset, + wc, wc - ONE_RUNNING)) { + int stat, c; long h; + while ((stat = joinMe.status) >= 0 && + (h = eventWaiters) != 0L && // help release others + (int)(h >>> EVENT_COUNT_SHIFT) != eventCount) + releaseEventWaiters(); + if (stat >= 0 && + ((workerCounts & RUNNING_COUNT_MASK) == 0 || + (stat = + joinMe.internalAwaitDone(JOIN_TIMEOUT_MILLIS)) >= 0)) + helpMaintainParallelism(); // timeout or no running workers + do {} while (!UNSAFE.compareAndSwapInt + (this, workerCountsOffset, + c = workerCounts, c + ONE_RUNNING)); + if (stat < 0) + break; // else restart + } + } + } + + /** + * Same idea as awaitJoin, but no helping, retries, or timeouts. + */ + final void awaitBlocker(ManagedBlocker blocker) + throws InterruptedException { + while (!blocker.isReleasable()) { + int wc = workerCounts; + if ((wc & RUNNING_COUNT_MASK) != 0 && + UNSAFE.compareAndSwapInt(this, workerCountsOffset, + wc, wc - ONE_RUNNING)) { + try { + while (!blocker.isReleasable()) { + long h = eventWaiters; + if (h != 0L && + (int)(h >>> EVENT_COUNT_SHIFT) != eventCount) + releaseEventWaiters(); + else if ((workerCounts & RUNNING_COUNT_MASK) == 0 && + runState < TERMINATING) + helpMaintainParallelism(); + else if (blocker.block()) + break; + } + } finally { + int c; + do {} while (!UNSAFE.compareAndSwapInt + (this, workerCountsOffset, + c = workerCounts, c + ONE_RUNNING)); + } + break; + } + } + } + + /** + * Possibly initiates and/or completes termination. + * + * @param now if true, unconditionally terminate, else only + * if shutdown and empty queue and no active workers + * @return true if now terminating or terminated + */ + private boolean tryTerminate(boolean now) { + if (now) + advanceRunLevel(SHUTDOWN); // ensure at least SHUTDOWN + else if (runState < SHUTDOWN || + !submissionQueue.isEmpty() || + (runState & ACTIVE_COUNT_MASK) != 0) + return false; + + if (advanceRunLevel(TERMINATING)) + startTerminating(); + + // Finish now if all threads terminated; else in some subsequent call + if ((workerCounts >>> TOTAL_COUNT_SHIFT) == 0) { + advanceRunLevel(TERMINATED); + termination.arrive(); + } + return true; + } + + /** + * Actions on transition to TERMINATING + * + * Runs up to four passes through workers: (0) shutting down each + * (without waking up if parked) to quickly spread notifications + * without unnecessary bouncing around event queues etc (1) wake + * up and help cancel tasks (2) interrupt (3) mop up races with + * interrupted workers + */ + private void startTerminating() { + cancelSubmissions(); + for (int passes = 0; passes < 4 && workerCounts != 0; ++passes) { + int c; // advance event count + UNSAFE.compareAndSwapInt(this, eventCountOffset, + c = eventCount, c+1); + eventWaiters = 0L; // clobber lists + spareWaiters = 0; + for (ForkJoinWorkerThread w : workers) { + if (w != null) { + w.shutdown(); + if (passes > 0 && !w.isTerminated()) { + w.cancelTasks(); + LockSupport.unpark(w); + if (passes > 1) { + try { + w.interrupt(); + } catch (SecurityException ignore) { + } + } + } + } + } + } + } + + /** + * Clears out and cancels submissions, ignoring exceptions. + */ + private void cancelSubmissions() { + ForkJoinTask task; + while ((task = submissionQueue.poll()) != null) { + try { + task.cancel(false); + } catch (Throwable ignore) { + } + } + } + + // misc support for ForkJoinWorkerThread + + /** + * Returns pool number. + */ + final int getPoolNumber() { + return poolNumber; + } + + /** + * Tries to accumulate steal count from a worker, clearing + * the worker's value if successful. + * + * @return true if worker steal count now zero + */ + final boolean tryAccumulateStealCount(ForkJoinWorkerThread w) { + int sc = w.stealCount; + long c = stealCount; + // CAS even if zero, for fence effects + if (UNSAFE.compareAndSwapLong(this, stealCountOffset, c, c + sc)) { + if (sc != 0) + w.stealCount = 0; + return true; + } + return sc == 0; + } + + /** + * Returns the approximate (non-atomic) number of idle threads per + * active thread. + */ + final int idlePerActive() { + int pc = parallelism; // use parallelism, not rc + int ac = runState; // no mask -- artificially boosts during shutdown + // Use exact results for small values, saturate past 4 + return ((pc <= ac) ? 0 : + (pc >>> 1 <= ac) ? 1 : + (pc >>> 2 <= ac) ? 3 : + pc >>> 3); + } + + // Public and protected methods // Constructors /** * Creates a {@code ForkJoinPool} with parallelism equal to {@link - * java.lang.Runtime#availableProcessors}, and using the {@linkplain - * #defaultForkJoinWorkerThreadFactory default thread factory}. + * java.lang.Runtime#availableProcessors}, using the {@linkplain + * #defaultForkJoinWorkerThreadFactory default thread factory}, + * no UncaughtExceptionHandler, and non-async LIFO processing mode. * * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads @@ -404,13 +1232,14 @@ public class ForkJoinPool extends AbstractExecutorService { */ public ForkJoinPool() { this(Runtime.getRuntime().availableProcessors(), - defaultForkJoinWorkerThreadFactory); + defaultForkJoinWorkerThreadFactory, null, false); } /** * Creates a {@code ForkJoinPool} with the indicated parallelism - * level and using the {@linkplain - * #defaultForkJoinWorkerThreadFactory default thread factory}. + * level, the {@linkplain + * #defaultForkJoinWorkerThreadFactory default thread factory}, + * no UncaughtExceptionHandler, and non-async LIFO processing mode. * * @param parallelism the parallelism level * @throws IllegalArgumentException if parallelism less than or @@ -421,31 +1250,25 @@ public class ForkJoinPool extends AbstractExecutorService { * java.lang.RuntimePermission}{@code ("modifyThread")} */ public ForkJoinPool(int parallelism) { - this(parallelism, defaultForkJoinWorkerThreadFactory); + this(parallelism, defaultForkJoinWorkerThreadFactory, null, false); } /** - * Creates a {@code ForkJoinPool} with parallelism equal to {@link - * java.lang.Runtime#availableProcessors}, and using the given - * thread factory. + * Creates a {@code ForkJoinPool} with the given parameters. * - * @param factory the factory for creating new threads - * @throws NullPointerException if the factory is null - * @throws SecurityException if a security manager exists and - * the caller is not permitted to modify threads - * because it does not hold {@link - * java.lang.RuntimePermission}{@code ("modifyThread")} - */ - public ForkJoinPool(ForkJoinWorkerThreadFactory factory) { - this(Runtime.getRuntime().availableProcessors(), factory); - } - - /** - * Creates a {@code ForkJoinPool} with the given parallelism and - * thread factory. - * - * @param parallelism the parallelism level - * @param factory the factory for creating new threads + * @param parallelism the parallelism level. For default value, + * use {@link java.lang.Runtime#availableProcessors}. + * @param factory the factory for creating new threads. For default value, + * use {@link #defaultForkJoinWorkerThreadFactory}. + * @param handler the handler for internal worker threads that + * terminate due to unrecoverable errors encountered while executing + * tasks. For default value, use {@code null}. + * @param asyncMode if true, + * establishes local first-in-first-out scheduling mode for forked + * tasks that are never joined. This mode may be more appropriate + * than default locally stack-based mode in applications in which + * worker threads only process event-style asynchronous tasks. + * For default value, use {@code false}. * @throws IllegalArgumentException if parallelism less than or * equal to zero, or greater than implementation limit * @throws NullPointerException if the factory is null @@ -454,153 +1277,40 @@ public class ForkJoinPool extends AbstractExecutorService { * because it does not hold {@link * java.lang.RuntimePermission}{@code ("modifyThread")} */ - public ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory) { - if (parallelism <= 0 || parallelism > MAX_THREADS) - throw new IllegalArgumentException(); + public ForkJoinPool(int parallelism, + ForkJoinWorkerThreadFactory factory, + Thread.UncaughtExceptionHandler handler, + boolean asyncMode) { + checkPermission(); if (factory == null) throw new NullPointerException(); - checkPermission(); - this.factory = factory; + if (parallelism <= 0 || parallelism > MAX_WORKERS) + throw new IllegalArgumentException(); this.parallelism = parallelism; - this.maxPoolSize = MAX_THREADS; - this.maintainsParallelism = true; - this.poolNumber = poolNumberGenerator.incrementAndGet(); - this.workerLock = new ReentrantLock(); - this.termination = workerLock.newCondition(); - this.stealCount = new AtomicLong(); + this.factory = factory; + this.ueh = handler; + this.locallyFifo = asyncMode; + int arraySize = initialArraySizeFor(parallelism); + this.workers = new ForkJoinWorkerThread[arraySize]; this.submissionQueue = new LinkedTransferQueue>(); - // worker array and workers are lazily constructed + this.workerLock = new ReentrantLock(); + this.termination = new Phaser(1); + this.poolNumber = poolNumberGenerator.incrementAndGet(); } /** - * Creates a new worker thread using factory. - * - * @param index the index to assign worker - * @return new worker, or null if factory failed + * Returns initial power of two size for workers array. + * @param pc the initial parallelism level */ - private ForkJoinWorkerThread createWorker(int index) { - Thread.UncaughtExceptionHandler h = ueh; - ForkJoinWorkerThread w = factory.newThread(this); - if (w != null) { - w.poolIndex = index; - w.setDaemon(true); - w.setAsyncMode(locallyFifo); - w.setName("ForkJoinPool-" + poolNumber + "-worker-" + index); - if (h != null) - w.setUncaughtExceptionHandler(h); - } - return w; - } - - /** - * Returns a good size for worker array given pool size. - * Currently requires size to be a power of two. - */ - private static int arraySizeFor(int poolSize) { - if (poolSize <= 1) - return 1; - // See Hackers Delight, sec 3.2 - int c = poolSize >= MAX_THREADS ? MAX_THREADS : (poolSize - 1); - c |= c >>> 1; - c |= c >>> 2; - c |= c >>> 4; - c |= c >>> 8; - c |= c >>> 16; - return c + 1; - } - - /** - * Creates or resizes array if necessary to hold newLength. - * Call only under exclusion. - * - * @return the array - */ - private ForkJoinWorkerThread[] ensureWorkerArrayCapacity(int newLength) { - ForkJoinWorkerThread[] ws = workers; - if (ws == null) - return workers = new ForkJoinWorkerThread[arraySizeFor(newLength)]; - else if (newLength > ws.length) - return workers = Arrays.copyOf(ws, arraySizeFor(newLength)); - else - return ws; - } - - /** - * Tries to shrink workers into smaller array after one or more terminate. - */ - private void tryShrinkWorkerArray() { - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - int len = ws.length; - int last = len - 1; - while (last >= 0 && ws[last] == null) - --last; - int newLength = arraySizeFor(last+1); - if (newLength < len) - workers = Arrays.copyOf(ws, newLength); - } - } - - /** - * Initializes workers if necessary. - */ - final void ensureWorkerInitialization() { - ForkJoinWorkerThread[] ws = workers; - if (ws == null) { - final ReentrantLock lock = this.workerLock; - lock.lock(); - try { - ws = workers; - if (ws == null) { - int ps = parallelism; - ws = ensureWorkerArrayCapacity(ps); - for (int i = 0; i < ps; ++i) { - ForkJoinWorkerThread w = createWorker(i); - if (w != null) { - ws[i] = w; - w.start(); - updateWorkerCount(1); - } - } - } - } finally { - lock.unlock(); - } - } - } - - /** - * Worker creation and startup for threads added via setParallelism. - */ - private void createAndStartAddedWorkers() { - resumeAllSpares(); // Allow spares to convert to nonspare - int ps = parallelism; - ForkJoinWorkerThread[] ws = ensureWorkerArrayCapacity(ps); - int len = ws.length; - // Sweep through slots, to keep lowest indices most populated - int k = 0; - while (k < len) { - if (ws[k] != null) { - ++k; - continue; - } - int s = workerCounts; - int tc = totalCountOf(s); - int rc = runningCountOf(s); - if (rc >= ps || tc >= ps) - break; - if (casWorkerCounts (s, workerCountsFor(tc+1, rc+1))) { - ForkJoinWorkerThread w = createWorker(k); - if (w != null) { - ws[k++] = w; - w.start(); - } - else { - updateWorkerCount(-1); // back out on failed creation - break; - } - } - } + private static int initialArraySizeFor(int pc) { + // If possible, initially allocate enough space for one spare + int size = pc < MAX_WORKERS ? pc + 1 : MAX_WORKERS; + // See Hackers Delight, sec 3.2. We know MAX_WORKERS < (1 >>> 16) + size |= size >>> 1; + size |= size >>> 2; + size |= size >>> 4; + size |= size >>> 8; + return size + 1; } // Execution methods @@ -611,12 +1321,12 @@ public class ForkJoinPool extends AbstractExecutorService { private void doSubmit(ForkJoinTask task) { if (task == null) throw new NullPointerException(); - if (isShutdown()) + if (runState >= SHUTDOWN) throw new RejectedExecutionException(); - if (workers == null) - ensureWorkerInitialization(); submissionQueue.offer(task); - signalIdleWorkers(); + int c; // try to increment event count -- CAS failure OK + UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1); + helpMaintainParallelism(); // create, start, or resume some workers } /** @@ -661,6 +1371,20 @@ public class ForkJoinPool extends AbstractExecutorService { doSubmit(job); } + /** + * Submits a ForkJoinTask for execution. + * + * @param task the task to submit + * @return the task + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public ForkJoinTask submit(ForkJoinTask task) { + doSubmit(task); + return task; + } + /** * @throws NullPointerException if the task is null * @throws RejectedExecutionException if the task cannot be @@ -698,21 +1422,6 @@ public class ForkJoinPool extends AbstractExecutorService { return job; } - /** - * Submits a ForkJoinTask for execution. - * - * @param task the task to submit - * @return the task - * @throws NullPointerException if the task is null - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - */ - public ForkJoinTask submit(ForkJoinTask task) { - doSubmit(task); - return task; - } - - /** * @throws NullPointerException {@inheritDoc} * @throws RejectedExecutionException {@inheritDoc} @@ -725,7 +1434,7 @@ public class ForkJoinPool extends AbstractExecutorService { invoke(new InvokeAll(forkJoinTasks)); @SuppressWarnings({"unchecked", "rawtypes"}) - List> futures = (List>) (List) forkJoinTasks; + List> futures = (List>) (List) forkJoinTasks; return futures; } @@ -739,8 +1448,6 @@ public class ForkJoinPool extends AbstractExecutorService { private static final long serialVersionUID = -7914297376763021607L; } - // Configuration and status settings and queries - /** * Returns the factory used for constructing new workers. * @@ -757,84 +1464,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the handler, or {@code null} if none */ public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { - Thread.UncaughtExceptionHandler h; - final ReentrantLock lock = this.workerLock; - lock.lock(); - try { - h = ueh; - } finally { - lock.unlock(); - } - return h; - } - - /** - * Sets the handler for internal worker threads that terminate due - * to unrecoverable errors encountered while executing tasks. - * Unless set, the current default or ThreadGroup handler is used - * as handler. - * - * @param h the new handler - * @return the old handler, or {@code null} if none - * @throws SecurityException if a security manager exists and - * the caller is not permitted to modify threads - * because it does not hold {@link - * java.lang.RuntimePermission}{@code ("modifyThread")} - */ - public Thread.UncaughtExceptionHandler - setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler h) { - checkPermission(); - Thread.UncaughtExceptionHandler old = null; - final ReentrantLock lock = this.workerLock; - lock.lock(); - try { - old = ueh; - ueh = h; - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - for (int i = 0; i < ws.length; ++i) { - ForkJoinWorkerThread w = ws[i]; - if (w != null) - w.setUncaughtExceptionHandler(h); - } - } - } finally { - lock.unlock(); - } - return old; - } - - - /** - * Sets the target parallelism level of this pool. - * - * @param parallelism the target parallelism - * @throws IllegalArgumentException if parallelism less than or - * equal to zero or greater than maximum size bounds - * @throws SecurityException if a security manager exists and - * the caller is not permitted to modify threads - * because it does not hold {@link - * java.lang.RuntimePermission}{@code ("modifyThread")} - */ - public void setParallelism(int parallelism) { - checkPermission(); - if (parallelism <= 0 || parallelism > maxPoolSize) - throw new IllegalArgumentException(); - final ReentrantLock lock = this.workerLock; - lock.lock(); - try { - if (isProcessingTasks()) { - int p = this.parallelism; - this.parallelism = parallelism; - if (parallelism > p) - createAndStartAddedWorkers(); - else - trimSpares(); - } - } finally { - lock.unlock(); - } - signalIdleWorkers(); + return ueh; } /** @@ -848,92 +1478,14 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Returns the number of worker threads that have started but not - * yet terminated. This result returned by this method may differ + * yet terminated. The result returned by this method may differ * from {@link #getParallelism} when threads are created to * maintain parallelism when others are cooperatively blocked. * * @return the number of worker threads */ public int getPoolSize() { - return totalCountOf(workerCounts); - } - - /** - * Returns the maximum number of threads allowed to exist in the - * pool. Unless set using {@link #setMaximumPoolSize}, the - * maximum is an implementation-defined value designed only to - * prevent runaway growth. - * - * @return the maximum - */ - public int getMaximumPoolSize() { - return maxPoolSize; - } - - /** - * Sets the maximum number of threads allowed to exist in the - * pool. The given value should normally be greater than or equal - * to the {@link #getParallelism parallelism} level. Setting this - * value has no effect on current pool size. It controls - * construction of new threads. - * - * @throws IllegalArgumentException if negative or greater than - * internal implementation limit - */ - public void setMaximumPoolSize(int newMax) { - if (newMax < 0 || newMax > MAX_THREADS) - throw new IllegalArgumentException(); - maxPoolSize = newMax; - } - - - /** - * Returns {@code true} if this pool dynamically maintains its - * target parallelism level. If false, new threads are added only - * to avoid possible starvation. This setting is by default true. - * - * @return {@code true} if maintains parallelism - */ - public boolean getMaintainsParallelism() { - return maintainsParallelism; - } - - /** - * Sets whether this pool dynamically maintains its target - * parallelism level. If false, new threads are added only to - * avoid possible starvation. - * - * @param enable {@code true} to maintain parallelism - */ - public void setMaintainsParallelism(boolean enable) { - maintainsParallelism = enable; - } - - /** - * Establishes local first-in-first-out scheduling mode for forked - * tasks that are never joined. This mode may be more appropriate - * than default locally stack-based mode in applications in which - * worker threads only process asynchronous tasks. This method is - * designed to be invoked only when the pool is quiescent, and - * typically only before any tasks are submitted. The effects of - * invocations at other times may be unpredictable. - * - * @param async if {@code true}, use locally FIFO scheduling - * @return the previous mode - * @see #getAsyncMode - */ - public boolean setAsyncMode(boolean async) { - boolean oldMode = locallyFifo; - locallyFifo = async; - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - for (int i = 0; i < ws.length; ++i) { - ForkJoinWorkerThread t = ws[i]; - if (t != null) - t.setAsyncMode(async); - } - } - return oldMode; + return workerCounts >>> TOTAL_COUNT_SHIFT; } /** @@ -941,7 +1493,6 @@ public class ForkJoinPool extends AbstractExecutorService { * scheduling mode for forked tasks that are never joined. * * @return {@code true} if this pool uses async mode - * @see #setAsyncMode */ public boolean getAsyncMode() { return locallyFifo; @@ -950,12 +1501,13 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Returns an estimate of the number of worker threads that are * not blocked waiting to join tasks or for other managed - * synchronization. + * synchronization. This method may overestimate the + * number of running threads. * * @return the number of worker threads */ public int getRunningThreadCount() { - return runningCountOf(workerCounts); + return workerCounts & RUNNING_COUNT_MASK; } /** @@ -966,19 +1518,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of active threads */ public int getActiveThreadCount() { - return activeCountOf(runControl); - } - - /** - * Returns an estimate of the number of threads that are currently - * idle waiting for tasks. This method may underestimate the - * number of idle threads. - * - * @return the number of idle threads - */ - final int getIdleThreadCount() { - int c = runningCountOf(workerCounts) - activeCountOf(runControl); - return (c <= 0) ? 0 : c; + return runState & ACTIVE_COUNT_MASK; } /** @@ -993,7 +1533,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if all threads are currently idle */ public boolean isQuiescent() { - return activeCountOf(runControl) == 0; + return (runState & ACTIVE_COUNT_MASK) == 0; } /** @@ -1008,17 +1548,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of steals */ public long getStealCount() { - return stealCount.get(); - } - - /** - * Accumulates steal count from a worker. - * Call only when worker known to be idle. - */ - private void updateStealCount(ForkJoinWorkerThread w) { - int sc = w.getAndClearStealCount(); - if (sc != 0) - stealCount.addAndGet(sc); + return stealCount; } /** @@ -1033,14 +1563,9 @@ public class ForkJoinPool extends AbstractExecutorService { */ public long getQueuedTaskCount() { long count = 0; - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - for (int i = 0; i < ws.length; ++i) { - ForkJoinWorkerThread t = ws[i]; - if (t != null) - count += t.getQueueSize(); - } - } + for (ForkJoinWorkerThread w : workers) + if (w != null) + count += w.getQueueSize(); return count; } @@ -1094,16 +1619,11 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the number of elements transferred */ protected int drainTasksTo(Collection> c) { - int n = submissionQueue.drainTo(c); - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - for (int i = 0; i < ws.length; ++i) { - ForkJoinWorkerThread w = ws[i]; - if (w != null) - n += w.drainTasksTo(c); - } - } - return n; + int count = submissionQueue.drainTo(c); + for (ForkJoinWorkerThread w : workers) + if (w != null) + count += w.drainTasksTo(c); + return count; } /** @@ -1114,36 +1634,34 @@ public class ForkJoinPool extends AbstractExecutorService { * @return a string identifying this pool, as well as its state */ public String toString() { - int ps = parallelism; - int wc = workerCounts; - int rc = runControl; long st = getStealCount(); long qt = getQueuedTaskCount(); long qs = getQueuedSubmissionCount(); + int wc = workerCounts; + int tc = wc >>> TOTAL_COUNT_SHIFT; + int rc = wc & RUNNING_COUNT_MASK; + int pc = parallelism; + int rs = runState; + int ac = rs & ACTIVE_COUNT_MASK; return super.toString() + - "[" + runStateToString(runStateOf(rc)) + - ", parallelism = " + ps + - ", size = " + totalCountOf(wc) + - ", active = " + activeCountOf(rc) + - ", running = " + runningCountOf(wc) + + "[" + runLevelToString(rs) + + ", parallelism = " + pc + + ", size = " + tc + + ", active = " + ac + + ", running = " + rc + ", steals = " + st + ", tasks = " + qt + ", submissions = " + qs + "]"; } - private static String runStateToString(int rs) { - switch(rs) { - case RUNNING: return "Running"; - case SHUTDOWN: return "Shutting down"; - case TERMINATING: return "Terminating"; - case TERMINATED: return "Terminated"; - default: throw new Error("Unknown run state"); - } + private static String runLevelToString(int s) { + return ((s & TERMINATED) != 0 ? "Terminated" : + ((s & TERMINATING) != 0 ? "Terminating" : + ((s & SHUTDOWN) != 0 ? "Shutting down" : + "Running"))); } - // lifecycle control - /** * Initiates an orderly shutdown in which previously submitted * tasks are executed, but no new tasks will be accepted. @@ -1158,23 +1676,8 @@ public class ForkJoinPool extends AbstractExecutorService { */ public void shutdown() { checkPermission(); - transitionRunStateTo(SHUTDOWN); - if (canTerminateOnShutdown(runControl)) { - if (workers == null) { // shutting down before workers created - final ReentrantLock lock = this.workerLock; - lock.lock(); - try { - if (workers == null) { - terminate(); - transitionRunStateTo(TERMINATED); - termination.signalAll(); - } - } finally { - lock.unlock(); - } - } - terminateOnShutdown(); - } + advanceRunLevel(SHUTDOWN); + tryTerminate(false); } /** @@ -1195,7 +1698,7 @@ public class ForkJoinPool extends AbstractExecutorService { */ public List shutdownNow() { checkPermission(); - terminate(); + tryTerminate(true); return Collections.emptyList(); } @@ -1205,7 +1708,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if all tasks have completed following shut down */ public boolean isTerminated() { - return runStateOf(runControl) == TERMINATED; + return runState >= TERMINATED; } /** @@ -1219,7 +1722,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if terminating but not yet terminated */ public boolean isTerminating() { - return runStateOf(runControl) == TERMINATING; + return (runState & (TERMINATING|TERMINATED)) == TERMINATING; } /** @@ -1228,15 +1731,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return {@code true} if this pool has been shut down */ public boolean isShutdown() { - return runStateOf(runControl) >= SHUTDOWN; - } - - /** - * Returns true if pool is not terminating or terminated. - * Used internally to suppress execution when terminating. - */ - final boolean isProcessingTasks() { - return runStateOf(runControl) < TERMINATING; + return runState >= SHUTDOWN; } /** @@ -1252,585 +1747,10 @@ public class ForkJoinPool extends AbstractExecutorService { */ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - long nanos = unit.toNanos(timeout); - final ReentrantLock lock = this.workerLock; - lock.lock(); try { - for (;;) { - if (isTerminated()) - return true; - if (nanos <= 0) - return false; - nanos = termination.awaitNanos(nanos); - } - } finally { - lock.unlock(); - } - } - - // Shutdown and termination support - - /** - * Callback from terminating worker. Nulls out the corresponding - * workers slot, and if terminating, tries to terminate; else - * tries to shrink workers array. - * - * @param w the worker - */ - final void workerTerminated(ForkJoinWorkerThread w) { - updateStealCount(w); - updateWorkerCount(-1); - final ReentrantLock lock = this.workerLock; - lock.lock(); - try { - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - int idx = w.poolIndex; - if (idx >= 0 && idx < ws.length && ws[idx] == w) - ws[idx] = null; - if (totalCountOf(workerCounts) == 0) { - terminate(); // no-op if already terminating - transitionRunStateTo(TERMINATED); - termination.signalAll(); - } - else if (isProcessingTasks()) { - tryShrinkWorkerArray(); - tryResumeSpare(true); // allow replacement - } - } - } finally { - lock.unlock(); - } - signalIdleWorkers(); - } - - /** - * Initiates termination. - */ - private void terminate() { - if (transitionRunStateTo(TERMINATING)) { - stopAllWorkers(); - resumeAllSpares(); - signalIdleWorkers(); - cancelQueuedSubmissions(); - cancelQueuedWorkerTasks(); - interruptUnterminatedWorkers(); - signalIdleWorkers(); // resignal after interrupt - } - } - - /** - * Possibly terminates when on shutdown state. - */ - private void terminateOnShutdown() { - if (!hasQueuedSubmissions() && canTerminateOnShutdown(runControl)) - terminate(); - } - - /** - * Clears out and cancels submissions. - */ - private void cancelQueuedSubmissions() { - ForkJoinTask task; - while ((task = pollSubmission()) != null) - task.cancel(false); - } - - /** - * Cleans out worker queues. - */ - private void cancelQueuedWorkerTasks() { - final ReentrantLock lock = this.workerLock; - lock.lock(); - try { - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - for (int i = 0; i < ws.length; ++i) { - ForkJoinWorkerThread t = ws[i]; - if (t != null) - t.cancelTasks(); - } - } - } finally { - lock.unlock(); - } - } - - /** - * Sets each worker's status to terminating. Requires lock to avoid - * conflicts with add/remove. - */ - private void stopAllWorkers() { - final ReentrantLock lock = this.workerLock; - lock.lock(); - try { - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - for (int i = 0; i < ws.length; ++i) { - ForkJoinWorkerThread t = ws[i]; - if (t != null) - t.shutdownNow(); - } - } - } finally { - lock.unlock(); - } - } - - /** - * Interrupts all unterminated workers. This is not required for - * sake of internal control, but may help unstick user code during - * shutdown. - */ - private void interruptUnterminatedWorkers() { - final ReentrantLock lock = this.workerLock; - lock.lock(); - try { - ForkJoinWorkerThread[] ws = workers; - if (ws != null) { - for (int i = 0; i < ws.length; ++i) { - ForkJoinWorkerThread t = ws[i]; - if (t != null && !t.isTerminated()) { - try { - t.interrupt(); - } catch (SecurityException ignore) { - } - } - } - } - } finally { - lock.unlock(); - } - } - - - /* - * Nodes for event barrier to manage idle threads. Queue nodes - * are basic Treiber stack nodes, also used for spare stack. - * - * The event barrier has an event count and a wait queue (actually - * a Treiber stack). Workers are enabled to look for work when - * the eventCount is incremented. If they fail to find work, they - * may wait for next count. Upon release, threads help others wake - * up. - * - * Synchronization events occur only in enough contexts to - * maintain overall liveness: - * - * - Submission of a new task to the pool - * - Resizes or other changes to the workers array - * - pool termination - * - A worker pushing a task on an empty queue - * - * The case of pushing a task occurs often enough, and is heavy - * enough compared to simple stack pushes, to require special - * handling: Method signalWork returns without advancing count if - * the queue appears to be empty. This would ordinarily result in - * races causing some queued waiters not to be woken up. To avoid - * this, the first worker enqueued in method sync (see - * syncIsReleasable) rescans for tasks after being enqueued, and - * helps signal if any are found. This works well because the - * worker has nothing better to do, and so might as well help - * alleviate the overhead and contention on the threads actually - * doing work. Also, since event counts increments on task - * availability exist to maintain liveness (rather than to force - * refreshes etc), it is OK for callers to exit early if - * contending with another signaller. - */ - static final class WaitQueueNode { - WaitQueueNode next; // only written before enqueued - volatile ForkJoinWorkerThread thread; // nulled to cancel wait - final long count; // unused for spare stack - - WaitQueueNode(long c, ForkJoinWorkerThread w) { - count = c; - thread = w; - } - - /** - * Wakes up waiter, returning false if known to already - */ - boolean signal() { - ForkJoinWorkerThread t = thread; - if (t == null) - return false; - thread = null; - LockSupport.unpark(t); - return true; - } - - /** - * Awaits release on sync. - */ - void awaitSyncRelease(ForkJoinPool p) { - while (thread != null && !p.syncIsReleasable(this)) - LockSupport.park(this); - } - - /** - * Awaits resumption as spare. - */ - void awaitSpareRelease() { - while (thread != null) { - if (!Thread.interrupted()) - LockSupport.park(this); - } - } - } - - /** - * Ensures that no thread is waiting for count to advance from the - * current value of eventCount read on entry to this method, by - * releasing waiting threads if necessary. - * - * @return the count - */ - final long ensureSync() { - long c = eventCount; - WaitQueueNode q; - while ((q = syncStack) != null && q.count < c) { - if (casBarrierStack(q, null)) { - do { - q.signal(); - } while ((q = q.next) != null); - break; - } - } - return c; - } - - /** - * Increments event count and releases waiting threads. - */ - private void signalIdleWorkers() { - long c; - do {} while (!casEventCount(c = eventCount, c+1)); - ensureSync(); - } - - /** - * Signals threads waiting to poll a task. Because method sync - * rechecks availability, it is OK to only proceed if queue - * appears to be non-empty, and OK to skip under contention to - * increment count (since some other thread succeeded). - */ - final void signalWork() { - long c; - WaitQueueNode q; - if (syncStack != null && - casEventCount(c = eventCount, c+1) && - (((q = syncStack) != null && q.count <= c) && - (!casBarrierStack(q, q.next) || !q.signal()))) - ensureSync(); - } - - /** - * Waits until event count advances from last value held by - * caller, or if excess threads, caller is resumed as spare, or - * caller or pool is terminating. Updates caller's event on exit. - * - * @param w the calling worker thread - */ - final void sync(ForkJoinWorkerThread w) { - updateStealCount(w); // Transfer w's count while it is idle - - while (!w.isShutdown() && isProcessingTasks() && !suspendIfSpare(w)) { - long prev = w.lastEventCount; - WaitQueueNode node = null; - WaitQueueNode h; - while (eventCount == prev && - ((h = syncStack) == null || h.count == prev)) { - if (node == null) - node = new WaitQueueNode(prev, w); - if (casBarrierStack(node.next = h, node)) { - node.awaitSyncRelease(this); - break; - } - } - long ec = ensureSync(); - if (ec != prev) { - w.lastEventCount = ec; - break; - } - } - } - - /** - * Returns {@code true} if worker waiting on sync can proceed: - * - on signal (thread == null) - * - on event count advance (winning race to notify vs signaller) - * - on interrupt - * - if the first queued node, we find work available - * If node was not signalled and event count not advanced on exit, - * then we also help advance event count. - * - * @return {@code true} if node can be released - */ - final boolean syncIsReleasable(WaitQueueNode node) { - long prev = node.count; - if (!Thread.interrupted() && node.thread != null && - (node.next != null || - !ForkJoinWorkerThread.hasQueuedTasks(workers)) && - eventCount == prev) + return termination.awaitAdvanceInterruptibly(0, timeout, unit) > 0; + } catch (TimeoutException ex) { return false; - if (node.thread != null) { - node.thread = null; - long ec = eventCount; - if (prev <= ec) // help signal - casEventCount(ec, ec+1); - } - return true; - } - - /** - * Returns {@code true} if a new sync event occurred since last - * call to sync or this method, if so, updating caller's count. - */ - final boolean hasNewSyncEvent(ForkJoinWorkerThread w) { - long lc = w.lastEventCount; - long ec = ensureSync(); - if (ec == lc) - return false; - w.lastEventCount = ec; - return true; - } - - // Parallelism maintenance - - /** - * Decrements running count; if too low, adds spare. - * - * Conceptually, all we need to do here is add or resume a - * spare thread when one is about to block (and remove or - * suspend it later when unblocked -- see suspendIfSpare). - * However, implementing this idea requires coping with - * several problems: we have imperfect information about the - * states of threads. Some count updates can and usually do - * lag run state changes, despite arrangements to keep them - * accurate (for example, when possible, updating counts - * before signalling or resuming), especially when running on - * dynamic JVMs that don't optimize the infrequent paths that - * update counts. Generating too many threads can make these - * problems become worse, because excess threads are more - * likely to be context-switched with others, slowing them all - * down, especially if there is no work available, so all are - * busy scanning or idling. Also, excess spare threads can - * only be suspended or removed when they are idle, not - * immediately when they aren't needed. So adding threads will - * raise parallelism level for longer than necessary. Also, - * FJ applications often encounter highly transient peaks when - * many threads are blocked joining, but for less time than it - * takes to create or resume spares. - * - * @param joinMe if non-null, return early if done - * @param maintainParallelism if true, try to stay within - * target counts, else create only to avoid starvation - * @return true if joinMe known to be done - */ - final boolean preJoin(ForkJoinTask joinMe, - boolean maintainParallelism) { - maintainParallelism &= maintainsParallelism; // overrride - boolean dec = false; // true when running count decremented - while (spareStack == null || !tryResumeSpare(dec)) { - int counts = workerCounts; - if (dec || (dec = casWorkerCounts(counts, --counts))) { - if (!needSpare(counts, maintainParallelism)) - break; - if (joinMe.status < 0) - return true; - if (tryAddSpare(counts)) - break; - } - } - return false; - } - - /** - * Same idea as preJoin - */ - final boolean preBlock(ManagedBlocker blocker, - boolean maintainParallelism) { - maintainParallelism &= maintainsParallelism; - boolean dec = false; - while (spareStack == null || !tryResumeSpare(dec)) { - int counts = workerCounts; - if (dec || (dec = casWorkerCounts(counts, --counts))) { - if (!needSpare(counts, maintainParallelism)) - break; - if (blocker.isReleasable()) - return true; - if (tryAddSpare(counts)) - break; - } - } - return false; - } - - /** - * Returns {@code true} if a spare thread appears to be needed. - * If maintaining parallelism, returns true when the deficit in - * running threads is more than the surplus of total threads, and - * there is apparently some work to do. This self-limiting rule - * means that the more threads that have already been added, the - * less parallelism we will tolerate before adding another. - * - * @param counts current worker counts - * @param maintainParallelism try to maintain parallelism - */ - private boolean needSpare(int counts, boolean maintainParallelism) { - int ps = parallelism; - int rc = runningCountOf(counts); - int tc = totalCountOf(counts); - int runningDeficit = ps - rc; - int totalSurplus = tc - ps; - return (tc < maxPoolSize && - (rc == 0 || totalSurplus < 0 || - (maintainParallelism && - runningDeficit > totalSurplus && - ForkJoinWorkerThread.hasQueuedTasks(workers)))); - } - - /** - * Adds a spare worker if lock available and no more than the - * expected numbers of threads exist. - * - * @return true if successful - */ - private boolean tryAddSpare(int expectedCounts) { - final ReentrantLock lock = this.workerLock; - int expectedRunning = runningCountOf(expectedCounts); - int expectedTotal = totalCountOf(expectedCounts); - boolean success = false; - boolean locked = false; - // confirm counts while locking; CAS after obtaining lock - try { - for (;;) { - int s = workerCounts; - int tc = totalCountOf(s); - int rc = runningCountOf(s); - if (rc > expectedRunning || tc > expectedTotal) - break; - if (!locked && !(locked = lock.tryLock())) - break; - if (casWorkerCounts(s, workerCountsFor(tc+1, rc+1))) { - createAndStartSpare(tc); - success = true; - break; - } - } - } finally { - if (locked) - lock.unlock(); - } - return success; - } - - /** - * Adds the kth spare worker. On entry, pool counts are already - * adjusted to reflect addition. - */ - private void createAndStartSpare(int k) { - ForkJoinWorkerThread w = null; - ForkJoinWorkerThread[] ws = ensureWorkerArrayCapacity(k + 1); - int len = ws.length; - // Probably, we can place at slot k. If not, find empty slot - if (k < len && ws[k] != null) { - for (k = 0; k < len && ws[k] != null; ++k) - ; - } - if (k < len && isProcessingTasks() && (w = createWorker(k)) != null) { - ws[k] = w; - w.start(); - } - else - updateWorkerCount(-1); // adjust on failure - signalIdleWorkers(); - } - - /** - * Suspends calling thread w if there are excess threads. Called - * only from sync. Spares are enqueued in a Treiber stack using - * the same WaitQueueNodes as barriers. They are resumed mainly - * in preJoin, but are also woken on pool events that require all - * threads to check run state. - * - * @param w the caller - */ - private boolean suspendIfSpare(ForkJoinWorkerThread w) { - WaitQueueNode node = null; - int s; - while (parallelism < runningCountOf(s = workerCounts)) { - if (node == null) - node = new WaitQueueNode(0, w); - if (casWorkerCounts(s, s-1)) { // representation-dependent - // push onto stack - do {} while (!casSpareStack(node.next = spareStack, node)); - // block until released by resumeSpare - node.awaitSpareRelease(); - return true; - } - } - return false; - } - - /** - * Tries to pop and resume a spare thread. - * - * @param updateCount if true, increment running count on success - * @return true if successful - */ - private boolean tryResumeSpare(boolean updateCount) { - WaitQueueNode q; - while ((q = spareStack) != null) { - if (casSpareStack(q, q.next)) { - if (updateCount) - updateRunningCount(1); - q.signal(); - return true; - } - } - return false; - } - - /** - * Pops and resumes all spare threads. Same idea as ensureSync. - * - * @return true if any spares released - */ - private boolean resumeAllSpares() { - WaitQueueNode q; - while ( (q = spareStack) != null) { - if (casSpareStack(q, null)) { - do { - updateRunningCount(1); - q.signal(); - } while ((q = q.next) != null); - return true; - } - } - return false; - } - - /** - * Pops and shuts down excessive spare threads. Call only while - * holding lock. This is not guaranteed to eliminate all excess - * threads, only those suspended as spares, which are the ones - * unlikely to be needed in the future. - */ - private void trimSpares() { - int surplus = totalCountOf(workerCounts) - parallelism; - WaitQueueNode q; - while (surplus > 0 && (q = spareStack) != null) { - if (casSpareStack(q, null)) { - do { - updateRunningCount(1); - ForkJoinWorkerThread w = q.thread; - if (w != null && surplus > 0 && - runningCountOf(workerCounts) > 0 && w.shutdown()) - --surplus; - q.signal(); - } while ((q = q.next) != null); - } } } @@ -1838,11 +1758,17 @@ public class ForkJoinPool extends AbstractExecutorService { * Interface for extending managed parallelism for tasks running * in {@link ForkJoinPool}s. * - *

    A {@code ManagedBlocker} provides two methods. - * Method {@code isReleasable} must return {@code true} if - * blocking is not necessary. Method {@code block} blocks the - * current thread if necessary (perhaps internally invoking - * {@code isReleasable} before actually blocking). + *

    A {@code ManagedBlocker} provides two methods. Method + * {@code isReleasable} must return {@code true} if blocking is + * not necessary. Method {@code block} blocks the current thread + * if necessary (perhaps internally invoking {@code isReleasable} + * before actually blocking). The unusual methods in this API + * accommodate synchronizers that may, but don't usually, block + * for long periods. Similarly, they allow more efficient internal + * handling of cases in which additional workers may be, but + * usually are not, needed to ensure sufficient parallelism. + * Toward this end, implementations of method {@code isReleasable} + * must be amenable to repeated invocation. * *

    For example, here is a ManagedBlocker based on a * ReentrantLock: @@ -1860,6 +1786,26 @@ public class ForkJoinPool extends AbstractExecutorService { * return hasLock || (hasLock = lock.tryLock()); * } * }}

    + * + *

    Here is a class that possibly blocks waiting for an + * item on a given queue: + *

     {@code
    +     * class QueueTaker implements ManagedBlocker {
    +     *   final BlockingQueue queue;
    +     *   volatile E item = null;
    +     *   QueueTaker(BlockingQueue q) { this.queue = q; }
    +     *   public boolean block() throws InterruptedException {
    +     *     if (item == null)
    +     *       item = queue.take();
    +     *     return true;
    +     *   }
    +     *   public boolean isReleasable() {
    +     *     return item != null || (item = queue.poll()) != null;
    +     *   }
    +     *   public E getItem() { // call after pool.managedBlock completes
    +     *     return item;
    +     *   }
    +     * }}
    */ public static interface ManagedBlocker { /** @@ -1883,14 +1829,7 @@ public class ForkJoinPool extends AbstractExecutorService { * Blocks in accord with the given blocker. If the current thread * is a {@link ForkJoinWorkerThread}, this method possibly * arranges for a spare thread to be activated if necessary to - * ensure parallelism while the current thread is blocked. - * - *

    If {@code maintainParallelism} is {@code true} and the pool - * supports it ({@link #getMaintainsParallelism}), this method - * attempts to maintain the pool's nominal parallelism. Otherwise - * it activates a thread only if necessary to avoid complete - * starvation. This option may be preferable when blockages use - * timeouts, or are almost always brief. + * ensure sufficient parallelism while the current thread is blocked. * *

    If the caller is not a {@link ForkJoinTask}, this method is * behaviorally equivalent to @@ -1904,33 +1843,18 @@ public class ForkJoinPool extends AbstractExecutorService { * first be expanded to ensure parallelism, and later adjusted. * * @param blocker the blocker - * @param maintainParallelism if {@code true} and supported by - * this pool, attempt to maintain the pool's nominal parallelism; - * otherwise activate a thread only if necessary to avoid - * complete starvation. * @throws InterruptedException if blocker.block did so */ - public static void managedBlock(ManagedBlocker blocker, - boolean maintainParallelism) + public static void managedBlock(ManagedBlocker blocker) throws InterruptedException { Thread t = Thread.currentThread(); - ForkJoinPool pool = ((t instanceof ForkJoinWorkerThread) ? - ((ForkJoinWorkerThread) t).pool : null); - if (!blocker.isReleasable()) { - try { - if (pool == null || - !pool.preBlock(blocker, maintainParallelism)) - awaitBlocker(blocker); - } finally { - if (pool != null) - pool.updateRunningCount(1); - } + if (t instanceof ForkJoinWorkerThread) { + ForkJoinWorkerThread w = (ForkJoinWorkerThread) t; + w.pool.awaitBlocker(blocker); + } + else { + do {} while (!blocker.isReleasable() && !blocker.block()); } - } - - private static void awaitBlocker(ManagedBlocker blocker) - throws InterruptedException { - do {} while (!blocker.isReleasable() && !blocker.block()); } // AbstractExecutorService overrides. These rely on undocumented @@ -1948,32 +1872,18 @@ public class ForkJoinPool extends AbstractExecutorService { // Unsafe mechanics private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); - private static final long eventCountOffset = - objectFieldOffset("eventCount", ForkJoinPool.class); private static final long workerCountsOffset = objectFieldOffset("workerCounts", ForkJoinPool.class); - private static final long runControlOffset = - objectFieldOffset("runControl", ForkJoinPool.class); - private static final long syncStackOffset = - objectFieldOffset("syncStack",ForkJoinPool.class); - private static final long spareStackOffset = - objectFieldOffset("spareStack", ForkJoinPool.class); - - private boolean casEventCount(long cmp, long val) { - return UNSAFE.compareAndSwapLong(this, eventCountOffset, cmp, val); - } - private boolean casWorkerCounts(int cmp, int val) { - return UNSAFE.compareAndSwapInt(this, workerCountsOffset, cmp, val); - } - private boolean casRunControl(int cmp, int val) { - return UNSAFE.compareAndSwapInt(this, runControlOffset, cmp, val); - } - private boolean casSpareStack(WaitQueueNode cmp, WaitQueueNode val) { - return UNSAFE.compareAndSwapObject(this, spareStackOffset, cmp, val); - } - private boolean casBarrierStack(WaitQueueNode cmp, WaitQueueNode val) { - return UNSAFE.compareAndSwapObject(this, syncStackOffset, cmp, val); - } + private static final long runStateOffset = + objectFieldOffset("runState", ForkJoinPool.class); + private static final long eventCountOffset = + objectFieldOffset("eventCount", ForkJoinPool.class); + private static final long eventWaitersOffset = + objectFieldOffset("eventWaiters", ForkJoinPool.class); + private static final long stealCountOffset = + objectFieldOffset("stealCount", ForkJoinPool.class); + private static final long spareWaitersOffset = + objectFieldOffset("spareWaiters", ForkJoinPool.class); private static long objectFieldOffset(String field, Class klazz) { try { diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java index 58f6e01b2af..598578f0cf1 100644 --- a/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java @@ -91,10 +91,7 @@ import java.util.WeakHashMap; * results of a task is {@link #join}, but there are several variants: * The {@link Future#get} methods support interruptible and/or timed * waits for completion and report results using {@code Future} - * conventions. Method {@link #helpJoin} enables callers to actively - * execute other tasks while awaiting joins, which is sometimes more - * efficient but only applies when all subtasks are known to be - * strictly tree-structured. Method {@link #invoke} is semantically + * conventions. Method {@link #invoke} is semantically * equivalent to {@code fork(); join()} but always attempts to begin * execution in the current thread. The "quiet" forms of * these methods do not extract results or report exceptions. These @@ -130,7 +127,7 @@ import java.util.WeakHashMap; * ForkJoinTasks (as may be determined using method {@link * #inForkJoinPool}). Attempts to invoke them in other contexts * result in exceptions or errors, possibly including - * ClassCastException. + * {@code ClassCastException}. * *

    Most base support methods are {@code final}, to prevent * overriding of implementations that are intrinsically tied to the @@ -152,9 +149,8 @@ import java.util.WeakHashMap; * *

    This class provides {@code adapt} methods for {@link Runnable} * and {@link Callable}, that may be of use when mixing execution of - * {@code ForkJoinTasks} with other kinds of tasks. When all tasks - * are of this form, consider using a pool in - * {@linkplain ForkJoinPool#setAsyncMode async mode}. + * {@code ForkJoinTasks} with other kinds of tasks. When all tasks are + * of this form, consider using a pool constructed in asyncMode. * *

    ForkJoinTasks are {@code Serializable}, which enables them to be * used in extensions such as remote execution frameworks. It is @@ -166,33 +162,43 @@ import java.util.WeakHashMap; */ public abstract class ForkJoinTask implements Future, Serializable { - /** - * Run control status bits packed into a single int to minimize - * footprint and to ensure atomicity (via CAS). Status is - * initially zero, and takes on nonnegative values until - * completed, upon which status holds COMPLETED. CANCELLED, or - * EXCEPTIONAL, which use the top 3 bits. Tasks undergoing - * blocking waits by other threads have SIGNAL_MASK bits set -- - * bit 15 for external (nonFJ) waits, and the rest a count of - * waiting FJ threads. (This representation relies on - * ForkJoinPool max thread limits). Completion of a stolen task - * with SIGNAL_MASK bits set awakens waiter via notifyAll. Even - * though suboptimal for some purposes, we use basic builtin - * wait/notify to take advantage of "monitor inflation" in JVMs - * that we would otherwise need to emulate to avoid adding further - * per-task bookkeeping overhead. Note that bits 16-28 are - * currently unused. Also value 0x80000000 is available as spare - * completion value. + /* + * See the internal documentation of class ForkJoinPool for a + * general implementation overview. ForkJoinTasks are mainly + * responsible for maintaining their "status" field amidst relays + * to methods in ForkJoinWorkerThread and ForkJoinPool. The + * methods of this class are more-or-less layered into (1) basic + * status maintenance (2) execution and awaiting completion (3) + * user-level methods that additionally report results. This is + * sometimes hard to see because this file orders exported methods + * in a way that flows well in javadocs. In particular, most + * join mechanics are in method quietlyJoin, below. */ + + /* + * The status field holds run control status bits packed into a + * single int to minimize footprint and to ensure atomicity (via + * CAS). Status is initially zero, and takes on nonnegative + * values until completed, upon which status holds value + * NORMAL, CANCELLED, or EXCEPTIONAL. Tasks undergoing blocking + * waits by other threads have the SIGNAL bit set. Completion of + * a stolen task with SIGNAL set awakens any waiters via + * notifyAll. Even though suboptimal for some purposes, we use + * basic builtin wait/notify to take advantage of "monitor + * inflation" in JVMs that we would otherwise need to emulate to + * avoid adding further per-task bookkeeping overhead. We want + * these monitors to be "fat", i.e., not use biasing or thin-lock + * techniques, so use some odd coding idioms that tend to avoid + * them. + */ + + /** The run status of this task */ volatile int status; // accessed directly by pool and workers - static final int COMPLETION_MASK = 0xe0000000; - static final int NORMAL = 0xe0000000; // == mask - static final int CANCELLED = 0xc0000000; - static final int EXCEPTIONAL = 0xa0000000; - static final int SIGNAL_MASK = 0x0000ffff; - static final int INTERNAL_SIGNAL_MASK = 0x00007fff; - static final int EXTERNAL_SIGNAL = 0x00008000; // top bit of low word + private static final int NORMAL = -1; + private static final int CANCELLED = -2; + private static final int EXCEPTIONAL = -3; + private static final int SIGNAL = 1; /** * Table of exceptions thrown by tasks, to enable reporting by @@ -206,176 +212,94 @@ public abstract class ForkJoinTask implements Future, Serializable { Collections.synchronizedMap (new WeakHashMap, Throwable>()); - // within-package utilities + // Maintaining completion status /** - * Gets current worker thread, or null if not a worker thread. - */ - static ForkJoinWorkerThread getWorker() { - Thread t = Thread.currentThread(); - return ((t instanceof ForkJoinWorkerThread) ? - (ForkJoinWorkerThread) t : null); - } - - final boolean casStatus(int cmp, int val) { - return UNSAFE.compareAndSwapInt(this, statusOffset, cmp, val); - } - - /** - * Workaround for not being able to rethrow unchecked exceptions. - */ - static void rethrowException(Throwable ex) { - if (ex != null) - UNSAFE.throwException(ex); - } - - // Setting completion status - - /** - * Marks completion and wakes up threads waiting to join this task. + * Marks completion and wakes up threads waiting to join this task, + * also clearing signal request bits. * * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL */ - final void setCompletion(int completion) { - ForkJoinPool pool = getPool(); - if (pool != null) { - int s; // Clear signal bits while setting completion status - do {} while ((s = status) >= 0 && !casStatus(s, completion)); - - if ((s & SIGNAL_MASK) != 0) { - if ((s &= INTERNAL_SIGNAL_MASK) != 0) - pool.updateRunningCount(s); - synchronized (this) { notifyAll(); } + private void setCompletion(int completion) { + int s; + while ((s = status) >= 0) { + if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) { + if (s != 0) + synchronized (this) { notifyAll(); } + break; } } - else - externallySetCompletion(completion); } /** - * Version of setCompletion for non-FJ threads. Leaves signal - * bits for unblocked threads to adjust, and always notifies. + * Records exception and sets exceptional completion. + * + * @return status on exit */ - private void externallySetCompletion(int completion) { - int s; - do {} while ((s = status) >= 0 && - !casStatus(s, (s & SIGNAL_MASK) | completion)); - synchronized (this) { notifyAll(); } + private void setExceptionalCompletion(Throwable rex) { + exceptionMap.put(this, rex); + setCompletion(EXCEPTIONAL); } /** - * Sets status to indicate normal completion. + * Blocks a worker thread until completion. Called only by + * pool. Currently unused -- pool-based waits use timeout + * version below. */ - final void setNormalCompletion() { - // Try typical fast case -- single CAS, no signal, not already done. - // Manually expand casStatus to improve chances of inlining it - if (!UNSAFE.compareAndSwapInt(this, statusOffset, 0, NORMAL)) - setCompletion(NORMAL); - } - - // internal waiting and notification - - /** - * Performs the actual monitor wait for awaitDone. - */ - private void doAwaitDone() { - // Minimize lock bias and in/de-flation effects by maximizing - // chances of waiting inside sync - try { - while (status >= 0) - synchronized (this) { if (status >= 0) wait(); } - } catch (InterruptedException ie) { - onInterruptedWait(); - } - } - - /** - * Performs the actual timed monitor wait for awaitDone. - */ - private void doAwaitDone(long startTime, long nanos) { - synchronized (this) { + final void internalAwaitDone() { + int s; // the odd construction reduces lock bias effects + while ((s = status) >= 0) { try { - while (status >= 0) { - long nt = nanos - (System.nanoTime() - startTime); - if (nt <= 0) - break; - wait(nt / 1000000, (int) (nt % 1000000)); + synchronized(this) { + if (UNSAFE.compareAndSwapInt(this, statusOffset, s,SIGNAL)) + wait(); } } catch (InterruptedException ie) { - onInterruptedWait(); + cancelIfTerminating(); } } } - // Awaiting completion - /** - * Sets status to indicate there is joiner, then waits for join, - * surrounded with pool notifications. + * Blocks a worker thread until completed or timed out. Called + * only by pool. * - * @return status upon exit + * @return status on exit */ - private int awaitDone(ForkJoinWorkerThread w, - boolean maintainParallelism) { - ForkJoinPool pool = (w == null) ? null : w.pool; + final int internalAwaitDone(long millis) { int s; - while ((s = status) >= 0) { - if (casStatus(s, (pool == null) ? s|EXTERNAL_SIGNAL : s+1)) { - if (pool == null || !pool.preJoin(this, maintainParallelism)) - doAwaitDone(); - if (((s = status) & INTERNAL_SIGNAL_MASK) != 0) - adjustPoolCountsOnUnblock(pool); - break; - } - } - return s; - } - - /** - * Timed version of awaitDone - * - * @return status upon exit - */ - private int awaitDone(ForkJoinWorkerThread w, long nanos) { - ForkJoinPool pool = (w == null) ? null : w.pool; - int s; - while ((s = status) >= 0) { - if (casStatus(s, (pool == null) ? s|EXTERNAL_SIGNAL : s+1)) { - long startTime = System.nanoTime(); - if (pool == null || !pool.preJoin(this, false)) - doAwaitDone(startTime, nanos); - if ((s = status) >= 0) { - adjustPoolCountsOnCancelledWait(pool); - s = status; + if ((s = status) >= 0) { + try { + synchronized(this) { + if (UNSAFE.compareAndSwapInt(this, statusOffset, s,SIGNAL)) + wait(millis, 0); } - if (s < 0 && (s & INTERNAL_SIGNAL_MASK) != 0) - adjustPoolCountsOnUnblock(pool); - break; + } catch (InterruptedException ie) { + cancelIfTerminating(); } + s = status; } return s; } /** - * Notifies pool that thread is unblocked. Called by signalled - * threads when woken by non-FJ threads (which is atypical). + * Blocks a non-worker-thread until completion. */ - private void adjustPoolCountsOnUnblock(ForkJoinPool pool) { + private void externalAwaitDone() { int s; - do {} while ((s = status) < 0 && !casStatus(s, s & COMPLETION_MASK)); - if (pool != null && (s &= INTERNAL_SIGNAL_MASK) != 0) - pool.updateRunningCount(s); - } - - /** - * Notifies pool to adjust counts on cancelled or timed out wait. - */ - private void adjustPoolCountsOnCancelledWait(ForkJoinPool pool) { - if (pool != null) { - int s; - while ((s = status) >= 0 && (s & INTERNAL_SIGNAL_MASK) != 0) { - if (casStatus(s, s - 1)) { - pool.updateRunningCount(1); + while ((s = status) >= 0) { + synchronized(this) { + if (UNSAFE.compareAndSwapInt(this, statusOffset, s, SIGNAL)){ + boolean interrupted = false; + while (status >= 0) { + try { + wait(); + } catch (InterruptedException ie) { + interrupted = true; + } + } + if (interrupted) + Thread.currentThread().interrupt(); break; } } @@ -383,153 +307,19 @@ public abstract class ForkJoinTask implements Future, Serializable { } /** - * Handles interruptions during waits. - */ - private void onInterruptedWait() { - ForkJoinWorkerThread w = getWorker(); - if (w == null) - Thread.currentThread().interrupt(); // re-interrupt - else if (w.isTerminating()) - cancelIgnoringExceptions(); - // else if FJworker, ignore interrupt - } - - // Recording and reporting exceptions - - private void setDoneExceptionally(Throwable rex) { - exceptionMap.put(this, rex); - setCompletion(EXCEPTIONAL); - } - - /** - * Throws the exception associated with status s. - * - * @throws the exception - */ - private void reportException(int s) { - if ((s &= COMPLETION_MASK) < NORMAL) { - if (s == CANCELLED) - throw new CancellationException(); - else - rethrowException(exceptionMap.get(this)); - } - } - - /** - * Returns result or throws exception using j.u.c.Future conventions. - * Only call when {@code isDone} known to be true or thread known - * to be interrupted. - */ - private V reportFutureResult() - throws InterruptedException, ExecutionException { - if (Thread.interrupted()) - throw new InterruptedException(); - int s = status & COMPLETION_MASK; - if (s < NORMAL) { - Throwable ex; - if (s == CANCELLED) - throw new CancellationException(); - if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) - throw new ExecutionException(ex); - } - return getRawResult(); - } - - /** - * Returns result or throws exception using j.u.c.Future conventions - * with timeouts. - */ - private V reportTimedFutureResult() - throws InterruptedException, ExecutionException, TimeoutException { - if (Thread.interrupted()) - throw new InterruptedException(); - Throwable ex; - int s = status & COMPLETION_MASK; - if (s == NORMAL) - return getRawResult(); - else if (s == CANCELLED) - throw new CancellationException(); - else if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) - throw new ExecutionException(ex); - else - throw new TimeoutException(); - } - - // internal execution methods - - /** - * Calls exec, recording completion, and rethrowing exception if - * encountered. Caller should normally check status before calling. - * - * @return true if completed normally - */ - private boolean tryExec() { - try { // try block must contain only call to exec - if (!exec()) - return false; - } catch (Throwable rex) { - setDoneExceptionally(rex); - rethrowException(rex); - return false; // not reached - } - setNormalCompletion(); - return true; - } - - /** - * Main execution method used by worker threads. Invokes - * base computation unless already complete. + * Unless done, calls exec and records status if completed, but + * doesn't wait for completion otherwise. Primary execution method + * for ForkJoinWorkerThread. */ final void quietlyExec() { - if (status >= 0) { - try { - if (!exec()) - return; - } catch (Throwable rex) { - setDoneExceptionally(rex); + try { + if (status < 0 || !exec()) return; - } - setNormalCompletion(); - } - } - - /** - * Calls exec(), recording but not rethrowing exception. - * Caller should normally check status before calling. - * - * @return true if completed normally - */ - private boolean tryQuietlyInvoke() { - try { - if (!exec()) - return false; } catch (Throwable rex) { - setDoneExceptionally(rex); - return false; + setExceptionalCompletion(rex); + return; } - setNormalCompletion(); - return true; - } - - /** - * Cancels, ignoring any exceptions it throws. - */ - final void cancelIgnoringExceptions() { - try { - cancel(false); - } catch (Throwable ignore) { - } - } - - /** - * Main implementation of helpJoin - */ - private int busyJoin(ForkJoinWorkerThread w) { - int s; - ForkJoinTask t; - while ((s = status) >= 0 && (t = w.scanWhileJoining(this)) != null) - t.quietlyExec(); - return (s >= 0) ? awaitDone(w, false) : s; // block if no work + setCompletion(NORMAL); // must be outside try block } // public methods @@ -567,34 +357,41 @@ public abstract class ForkJoinTask implements Future, Serializable { * @return the computed result */ public final V join() { - ForkJoinWorkerThread w = getWorker(); - if (w == null || status < 0 || !w.unpushTask(this) || !tryExec()) - reportException(awaitDone(w, true)); + quietlyJoin(); + Throwable ex; + if (status < NORMAL && (ex = getException()) != null) + UNSAFE.throwException(ex); return getRawResult(); } /** * Commences performing this task, awaits its completion if - * necessary, and return its result, or throws an (unchecked) - * exception if the underlying computation did so. + * necessary, and returns its result, or throws an (unchecked) + * {@code RuntimeException} or {@code Error} if the underlying + * computation did so. * * @return the computed result */ public final V invoke() { - if (status >= 0 && tryExec()) - return getRawResult(); - else - return join(); + quietlyInvoke(); + Throwable ex; + if (status < NORMAL && (ex = getException()) != null) + UNSAFE.throwException(ex); + return getRawResult(); } /** * Forks the given tasks, returning when {@code isDone} holds for * each task or an (unchecked) exception is encountered, in which - * case the exception is rethrown. If either task encounters an - * exception, the other one may be, but is not guaranteed to be, - * cancelled. If both tasks throw an exception, then this method - * throws one of them. The individual status of each task may be - * checked using {@link #getException()} and related methods. + * case the exception is rethrown. If more than one task + * encounters an exception, then this method throws any one of + * these exceptions. If any task encounters an exception, the + * other may be cancelled. However, the execution status of + * individual tasks is not guaranteed upon exceptional return. The + * status of each task may be obtained using {@link + * #getException()} and related methods to check if they have been + * cancelled, completed normally or exceptionally, or left + * unprocessed. * *

    This method may be invoked only from within {@code * ForkJoinTask} computations (as may be determined using method @@ -615,12 +412,14 @@ public abstract class ForkJoinTask implements Future, Serializable { /** * Forks the given tasks, returning when {@code isDone} holds for * each task or an (unchecked) exception is encountered, in which - * case the exception is rethrown. If any task encounters an - * exception, others may be, but are not guaranteed to be, - * cancelled. If more than one task encounters an exception, then - * this method throws any one of these exceptions. The individual - * status of each task may be checked using {@link #getException()} - * and related methods. + * case the exception is rethrown. If more than one task + * encounters an exception, then this method throws any one of + * these exceptions. If any task encounters an exception, others + * may be cancelled. However, the execution status of individual + * tasks is not guaranteed upon exceptional return. The status of + * each task may be obtained using {@link #getException()} and + * related methods to check if they have been cancelled, completed + * normally or exceptionally, or left unprocessed. * *

    This method may be invoked only from within {@code * ForkJoinTask} computations (as may be determined using method @@ -644,7 +443,7 @@ public abstract class ForkJoinTask implements Future, Serializable { t.fork(); else { t.quietlyInvoke(); - if (ex == null) + if (ex == null && t.status < NORMAL) ex = t.getException(); } } @@ -655,26 +454,27 @@ public abstract class ForkJoinTask implements Future, Serializable { t.cancel(false); else { t.quietlyJoin(); - if (ex == null) + if (ex == null && t.status < NORMAL) ex = t.getException(); } } } if (ex != null) - rethrowException(ex); + UNSAFE.throwException(ex); } /** * Forks all tasks in the specified collection, returning when * {@code isDone} holds for each task or an (unchecked) exception - * is encountered. If any task encounters an exception, others - * may be, but are not guaranteed to be, cancelled. If more than - * one task encounters an exception, then this method throws any - * one of these exceptions. The individual status of each task - * may be checked using {@link #getException()} and related - * methods. The behavior of this operation is undefined if the - * specified collection is modified while the operation is in - * progress. + * is encountered, in which case the exception is rethrown. If + * more than one task encounters an exception, then this method + * throws any one of these exceptions. If any task encounters an + * exception, others may be cancelled. However, the execution + * status of individual tasks is not guaranteed upon exceptional + * return. The status of each task may be obtained using {@link + * #getException()} and related methods to check if they have been + * cancelled, completed normally or exceptionally, or left + * unprocessed. * *

    This method may be invoked only from within {@code * ForkJoinTask} computations (as may be determined using method @@ -706,7 +506,7 @@ public abstract class ForkJoinTask implements Future, Serializable { t.fork(); else { t.quietlyInvoke(); - if (ex == null) + if (ex == null && t.status < NORMAL) ex = t.getException(); } } @@ -717,13 +517,13 @@ public abstract class ForkJoinTask implements Future, Serializable { t.cancel(false); else { t.quietlyJoin(); - if (ex == null) + if (ex == null && t.status < NORMAL) ex = t.getException(); } } } if (ex != null) - rethrowException(ex); + UNSAFE.throwException(ex); return tasks; } @@ -753,7 +553,35 @@ public abstract class ForkJoinTask implements Future, Serializable { */ public boolean cancel(boolean mayInterruptIfRunning) { setCompletion(CANCELLED); - return (status & COMPLETION_MASK) == CANCELLED; + return status == CANCELLED; + } + + /** + * Cancels, ignoring any exceptions thrown by cancel. Used during + * worker and pool shutdown. Cancel is spec'ed not to throw any + * exceptions, but if it does anyway, we have no recourse during + * shutdown, so guard against this case. + */ + final void cancelIgnoringExceptions() { + try { + cancel(false); + } catch (Throwable ignore) { + } + } + + /** + * Cancels if current thread is a terminating worker thread, + * ignoring any exceptions thrown by cancel. + */ + final void cancelIfTerminating() { + Thread t = Thread.currentThread(); + if ((t instanceof ForkJoinWorkerThread) && + ((ForkJoinWorkerThread) t).isTerminating()) { + try { + cancel(false); + } catch (Throwable ignore) { + } + } } public final boolean isDone() { @@ -761,7 +589,7 @@ public abstract class ForkJoinTask implements Future, Serializable { } public final boolean isCancelled() { - return (status & COMPLETION_MASK) == CANCELLED; + return status == CANCELLED; } /** @@ -770,7 +598,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * @return {@code true} if this task threw an exception or was cancelled */ public final boolean isCompletedAbnormally() { - return (status & COMPLETION_MASK) < NORMAL; + return status < NORMAL; } /** @@ -781,7 +609,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * exception and was not cancelled */ public final boolean isCompletedNormally() { - return (status & COMPLETION_MASK) == NORMAL; + return status == NORMAL; } /** @@ -792,7 +620,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * @return the exception, or {@code null} if none */ public final Throwable getException() { - int s = status & COMPLETION_MASK; + int s = status; return ((s >= NORMAL) ? null : (s == CANCELLED) ? new CancellationException() : exceptionMap.get(this)); @@ -813,20 +641,21 @@ public abstract class ForkJoinTask implements Future, Serializable { * thrown will be a {@code RuntimeException} with cause {@code ex}. */ public void completeExceptionally(Throwable ex) { - setDoneExceptionally((ex instanceof RuntimeException) || - (ex instanceof Error) ? ex : - new RuntimeException(ex)); + setExceptionalCompletion((ex instanceof RuntimeException) || + (ex instanceof Error) ? ex : + new RuntimeException(ex)); } /** * Completes this task, and if not already aborted or cancelled, - * returning a {@code null} result upon {@code join} and related - * operations. This method may be used to provide results for - * asynchronous tasks, or to provide alternative handling for - * tasks that would not otherwise complete normally. Its use in - * other situations is discouraged. This method is - * overridable, but overridden versions must invoke {@code super} - * implementation to maintain guarantees. + * returning the given value as the result of subsequent + * invocations of {@code join} and related operations. This method + * may be used to provide results for asynchronous tasks, or to + * provide alternative handling for tasks that would not otherwise + * complete normally. Its use in other situations is + * discouraged. This method is overridable, but overridden + * versions must invoke {@code super} implementation to maintain + * guarantees. * * @param value the result value for this task */ @@ -834,97 +663,151 @@ public abstract class ForkJoinTask implements Future, Serializable { try { setRawResult(value); } catch (Throwable rex) { - setDoneExceptionally(rex); + setExceptionalCompletion(rex); return; } - setNormalCompletion(); + setCompletion(NORMAL); } public final V get() throws InterruptedException, ExecutionException { - ForkJoinWorkerThread w = getWorker(); - if (w == null || status < 0 || !w.unpushTask(this) || !tryQuietlyInvoke()) - awaitDone(w, true); - return reportFutureResult(); + quietlyJoin(); + if (Thread.interrupted()) + throw new InterruptedException(); + int s = status; + if (s < NORMAL) { + Throwable ex; + if (s == CANCELLED) + throw new CancellationException(); + if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) + throw new ExecutionException(ex); + } + return getRawResult(); } public final V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + Thread t = Thread.currentThread(); + ForkJoinPool pool; + if (t instanceof ForkJoinWorkerThread) { + ForkJoinWorkerThread w = (ForkJoinWorkerThread) t; + if (status >= 0 && w.unpushTask(this)) + quietlyExec(); + pool = w.pool; + } + else + pool = null; + /* + * Timed wait loop intermixes cases for FJ (pool != null) and + * non FJ threads. For FJ, decrement pool count but don't try + * for replacement; increment count on completion. For non-FJ, + * deal with interrupts. This is messy, but a little less so + * than is splitting the FJ and nonFJ cases. + */ + boolean interrupted = false; + boolean dec = false; // true if pool count decremented long nanos = unit.toNanos(timeout); - ForkJoinWorkerThread w = getWorker(); - if (w == null || status < 0 || !w.unpushTask(this) || !tryQuietlyInvoke()) - awaitDone(w, nanos); - return reportTimedFutureResult(); - } - - /** - * Possibly executes other tasks until this task {@link #isDone is - * done}, then returns the result of the computation. This method - * may be more efficient than {@code join}, but is only applicable - * when there are no potential dependencies between continuation - * of the current task and that of any other task that might be - * executed while helping. (This usually holds for pure - * divide-and-conquer tasks). - * - *

    This method may be invoked only from within {@code - * ForkJoinTask} computations (as may be determined using method - * {@link #inForkJoinPool}). Attempts to invoke in other contexts - * result in exceptions or errors, possibly including {@code - * ClassCastException}. - * - * @return the computed result - */ - public final V helpJoin() { - ForkJoinWorkerThread w = (ForkJoinWorkerThread) Thread.currentThread(); - if (status < 0 || !w.unpushTask(this) || !tryExec()) - reportException(busyJoin(w)); + for (;;) { + if (pool == null && Thread.interrupted()) { + interrupted = true; + break; + } + int s = status; + if (s < 0) + break; + if (UNSAFE.compareAndSwapInt(this, statusOffset, s, SIGNAL)) { + long startTime = System.nanoTime(); + long nt; // wait time + while (status >= 0 && + (nt = nanos - (System.nanoTime() - startTime)) > 0) { + if (pool != null && !dec) + dec = pool.tryDecrementRunningCount(); + else { + long ms = nt / 1000000; + int ns = (int) (nt % 1000000); + try { + synchronized(this) { + if (status >= 0) + wait(ms, ns); + } + } catch (InterruptedException ie) { + if (pool != null) + cancelIfTerminating(); + else { + interrupted = true; + break; + } + } + } + } + break; + } + } + if (pool != null && dec) + pool.incrementRunningCount(); + if (interrupted) + throw new InterruptedException(); + int es = status; + if (es != NORMAL) { + Throwable ex; + if (es == CANCELLED) + throw new CancellationException(); + if (es == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) + throw new ExecutionException(ex); + throw new TimeoutException(); + } return getRawResult(); } /** - * Possibly executes other tasks until this task {@link #isDone is - * done}. This method may be useful when processing collections - * of tasks when some have been cancelled or otherwise known to - * have aborted. - * - *

    This method may be invoked only from within {@code - * ForkJoinTask} computations (as may be determined using method - * {@link #inForkJoinPool}). Attempts to invoke in other contexts - * result in exceptions or errors, possibly including {@code - * ClassCastException}. - */ - public final void quietlyHelpJoin() { - if (status >= 0) { - ForkJoinWorkerThread w = - (ForkJoinWorkerThread) Thread.currentThread(); - if (!w.unpushTask(this) || !tryQuietlyInvoke()) - busyJoin(w); - } - } - - /** - * Joins this task, without returning its result or throwing an + * Joins this task, without returning its result or throwing its * exception. This method may be useful when processing * collections of tasks when some have been cancelled or otherwise * known to have aborted. */ public final void quietlyJoin() { - if (status >= 0) { - ForkJoinWorkerThread w = getWorker(); - if (w == null || !w.unpushTask(this) || !tryQuietlyInvoke()) - awaitDone(w, true); + Thread t; + if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) { + ForkJoinWorkerThread w = (ForkJoinWorkerThread) t; + if (status >= 0) { + if (w.unpushTask(this)) { + boolean completed; + try { + completed = exec(); + } catch (Throwable rex) { + setExceptionalCompletion(rex); + return; + } + if (completed) { + setCompletion(NORMAL); + return; + } + } + w.joinTask(this); + } } + else + externalAwaitDone(); } /** * Commences performing this task and awaits its completion if - * necessary, without returning its result or throwing an - * exception. This method may be useful when processing - * collections of tasks when some have been cancelled or otherwise - * known to have aborted. + * necessary, without returning its result or throwing its + * exception. */ public final void quietlyInvoke() { - if (status >= 0 && !tryQuietlyInvoke()) - quietlyJoin(); + if (status >= 0) { + boolean completed; + try { + completed = exec(); + } catch (Throwable rex) { + setExceptionalCompletion(rex); + return; + } + if (completed) + setCompletion(NORMAL); + else + quietlyJoin(); + } } /** @@ -956,7 +839,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * pre-constructed trees of subtasks in loops. */ public void reinitialize() { - if ((status & COMPLETION_MASK) == EXCEPTIONAL) + if (status == EXCEPTIONAL) exceptionMap.remove(this); status = 0; } @@ -1246,7 +1129,7 @@ public abstract class ForkJoinTask implements Future, Serializable { private static final long serialVersionUID = -7721805057305804111L; /** - * Saves the state to a stream. + * Saves the state to a stream (that is, serializes it). * * @serialData the current run status and the exception thrown * during execution, or {@code null} if none @@ -1259,18 +1142,16 @@ public abstract class ForkJoinTask implements Future, Serializable { } /** - * Reconstitutes the instance from a stream. + * Reconstitutes the instance from a stream (that is, deserializes it). * * @param s the stream */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); - status &= ~INTERNAL_SIGNAL_MASK; // clear internal signal counts - status |= EXTERNAL_SIGNAL; // conservatively set external signal Object ex = s.readObject(); if (ex != null) - setDoneExceptionally((Throwable) ex); + setExceptionalCompletion((Throwable) ex); } // Unsafe mechanics diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java index 0dc14c71a2d..784dd8056bc 100644 --- a/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java +++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java @@ -35,7 +35,9 @@ package java.util.concurrent; +import java.util.Random; import java.util.Collection; +import java.util.concurrent.locks.LockSupport; /** * A thread managed by a {@link ForkJoinPool}. This class is @@ -52,46 +54,55 @@ import java.util.Collection; */ public class ForkJoinWorkerThread extends Thread { /* - * Algorithm overview: + * Overview: * - * 1. Work-Stealing: Work-stealing queues are special forms of - * Deques that support only three of the four possible - * end-operations -- push, pop, and deq (aka steal), and only do - * so under the constraints that push and pop are called only from - * the owning thread, while deq may be called from other threads. - * (If you are unfamiliar with them, you probably want to read - * Herlihy and Shavit's book "The Art of Multiprocessor - * programming", chapter 16 describing these in more detail before - * proceeding.) The main work-stealing queue design is roughly - * similar to "Dynamic Circular Work-Stealing Deque" by David - * Chase and Yossi Lev, SPAA 2005 - * (http://research.sun.com/scalable/pubs/index.html). The main - * difference ultimately stems from gc requirements that we null - * out taken slots as soon as we can, to maintain as small a - * footprint as possible even in programs generating huge numbers - * of tasks. To accomplish this, we shift the CAS arbitrating pop - * vs deq (steal) from being on the indices ("base" and "sp") to - * the slots themselves (mainly via method "casSlotNull()"). So, - * both a successful pop and deq mainly entail CAS'ing a non-null - * slot to null. Because we rely on CASes of references, we do - * not need tag bits on base or sp. They are simple ints as used - * in any circular array-based queue (see for example ArrayDeque). - * Updates to the indices must still be ordered in a way that - * guarantees that (sp - base) > 0 means the queue is empty, but - * otherwise may err on the side of possibly making the queue - * appear nonempty when a push, pop, or deq have not fully - * committed. Note that this means that the deq operation, - * considered individually, is not wait-free. One thief cannot - * successfully continue until another in-progress one (or, if - * previously empty, a push) completes. However, in the - * aggregate, we ensure at least probabilistic - * non-blockingness. If an attempted steal fails, a thief always - * chooses a different random victim target to try next. So, in - * order for one thief to progress, it suffices for any - * in-progress deq or new push on any empty queue to complete. One - * reason this works well here is that apparently-nonempty often - * means soon-to-be-stealable, which gives threads a chance to - * activate if necessary before stealing (see below). + * ForkJoinWorkerThreads are managed by ForkJoinPools and perform + * ForkJoinTasks. This class includes bookkeeping in support of + * worker activation, suspension, and lifecycle control described + * in more detail in the internal documentation of class + * ForkJoinPool. And as described further below, this class also + * includes special-cased support for some ForkJoinTask + * methods. But the main mechanics involve work-stealing: + * + * Work-stealing queues are special forms of Deques that support + * only three of the four possible end-operations -- push, pop, + * and deq (aka steal), under the further constraints that push + * and pop are called only from the owning thread, while deq may + * be called from other threads. (If you are unfamiliar with + * them, you probably want to read Herlihy and Shavit's book "The + * Art of Multiprocessor programming", chapter 16 describing these + * in more detail before proceeding.) The main work-stealing + * queue design is roughly similar to those in the papers "Dynamic + * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005 + * (http://research.sun.com/scalable/pubs/index.html) and + * "Idempotent work stealing" by Michael, Saraswat, and Vechev, + * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186). + * The main differences ultimately stem from gc requirements that + * we null out taken slots as soon as we can, to maintain as small + * a footprint as possible even in programs generating huge + * numbers of tasks. To accomplish this, we shift the CAS + * arbitrating pop vs deq (steal) from being on the indices + * ("base" and "sp") to the slots themselves (mainly via method + * "casSlotNull()"). So, both a successful pop and deq mainly + * entail a CAS of a slot from non-null to null. Because we rely + * on CASes of references, we do not need tag bits on base or sp. + * They are simple ints as used in any circular array-based queue + * (see for example ArrayDeque). Updates to the indices must + * still be ordered in a way that guarantees that sp == base means + * the queue is empty, but otherwise may err on the side of + * possibly making the queue appear nonempty when a push, pop, or + * deq have not fully committed. Note that this means that the deq + * operation, considered individually, is not wait-free. One thief + * cannot successfully continue until another in-progress one (or, + * if previously empty, a push) completes. However, in the + * aggregate, we ensure at least probabilistic non-blockingness. + * If an attempted steal fails, a thief always chooses a different + * random victim target to try next. So, in order for one thief to + * progress, it suffices for any in-progress deq or new push on + * any empty queue to complete. One reason this works well here is + * that apparently-nonempty often means soon-to-be-stealable, + * which gives threads a chance to set activation status if + * necessary before stealing. * * This approach also enables support for "async mode" where local * task processing is in FIFO, not LIFO order; simply by using a @@ -99,24 +110,54 @@ public class ForkJoinWorkerThread extends Thread { * by the ForkJoinPool). This allows use in message-passing * frameworks in which tasks are never joined. * - * Efficient implementation of this approach currently relies on - * an uncomfortable amount of "Unsafe" mechanics. To maintain + * When a worker would otherwise be blocked waiting to join a + * task, it first tries a form of linear helping: Each worker + * records (in field currentSteal) the most recent task it stole + * from some other worker. Plus, it records (in field currentJoin) + * the task it is currently actively joining. Method joinTask uses + * these markers to try to find a worker to help (i.e., steal back + * a task from and execute it) that could hasten completion of the + * actively joined task. In essence, the joiner executes a task + * that would be on its own local deque had the to-be-joined task + * not been stolen. This may be seen as a conservative variant of + * the approach in Wagner & Calder "Leapfrogging: a portable + * technique for implementing efficient futures" SIGPLAN Notices, + * 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs + * in that: (1) We only maintain dependency links across workers + * upon steals, rather than use per-task bookkeeping. This may + * require a linear scan of workers array to locate stealers, but + * usually doesn't because stealers leave hints (that may become + * stale/wrong) of where to locate them. This isolates cost to + * when it is needed, rather than adding to per-task overhead. + * (2) It is "shallow", ignoring nesting and potentially cyclic + * mutual steals. (3) It is intentionally racy: field currentJoin + * is updated only while actively joining, which means that we + * miss links in the chain during long-lived tasks, GC stalls etc + * (which is OK since blocking in such cases is usually a good + * idea). (4) We bound the number of attempts to find work (see + * MAX_HELP_DEPTH) and fall back to suspending the worker and if + * necessary replacing it with a spare (see + * ForkJoinPool.awaitJoin). + * + * Efficient implementation of these algorithms currently relies + * on an uncomfortable amount of "Unsafe" mechanics. To maintain * correct orderings, reads and writes of variable base require - * volatile ordering. Variable sp does not require volatile write - * but needs cheaper store-ordering on writes. Because they are - * protected by volatile base reads, reads of the queue array and - * its slots do not need volatile load semantics, but writes (in - * push) require store order and CASes (in pop and deq) require - * (volatile) CAS semantics. (See "Idempotent work stealing" by - * Michael, Saraswat, and Vechev, PPoPP 2009 - * http://portal.acm.org/citation.cfm?id=1504186 for an algorithm - * with similar properties, but without support for nulling - * slots.) Since these combinations aren't supported using - * ordinary volatiles, the only way to accomplish these - * efficiently is to use direct Unsafe calls. (Using external - * AtomicIntegers and AtomicReferenceArrays for the indices and - * array is significantly slower because of memory locality and - * indirection effects.) + * volatile ordering. Variable sp does not require volatile + * writes but still needs store-ordering, which we accomplish by + * pre-incrementing sp before filling the slot with an ordered + * store. (Pre-incrementing also enables backouts used in + * joinTask.) Because they are protected by volatile base reads, + * reads of the queue array and its slots by other threads do not + * need volatile load semantics, but writes (in push) require + * store order and CASes (in pop and deq) require (volatile) CAS + * semantics. (Michael, Saraswat, and Vechev's algorithm has + * similar properties, but without support for nulling slots.) + * Since these combinations aren't supported using ordinary + * volatiles, the only way to accomplish these efficiently is to + * use direct Unsafe calls. (Using external AtomicIntegers and + * AtomicReferenceArrays for the indices and array is + * significantly slower because of memory locality and indirection + * effects.) * * Further, performance on most platforms is very sensitive to * placement and sizing of the (resizable) queue array. Even @@ -124,56 +165,45 @@ public class ForkJoinWorkerThread extends Thread { * initial size must be large enough to counteract cache * contention effects across multiple queues (especially in the * presence of GC cardmarking). Also, to improve thread-locality, - * queues are currently initialized immediately after the thread - * gets the initial signal to start processing tasks. However, - * all queue-related methods except pushTask are written in a way - * that allows them to instead be lazily allocated and/or disposed - * of when empty. All together, these low-level implementation - * choices produce as much as a factor of 4 performance - * improvement compared to naive implementations, and enable the - * processing of billions of tasks per second, sometimes at the - * expense of ugliness. - * - * 2. Run control: The primary run control is based on a global - * counter (activeCount) held by the pool. It uses an algorithm - * similar to that in Herlihy and Shavit section 17.6 to cause - * threads to eventually block when all threads declare they are - * inactive. For this to work, threads must be declared active - * when executing tasks, and before stealing a task. They must be - * inactive before blocking on the Pool Barrier (awaiting a new - * submission or other Pool event). In between, there is some free - * play which we take advantage of to avoid contention and rapid - * flickering of the global activeCount: If inactive, we activate - * only if a victim queue appears to be nonempty (see above). - * Similarly, a thread tries to inactivate only after a full scan - * of other threads. The net effect is that contention on - * activeCount is rarely a measurable performance issue. (There - * are also a few other cases where we scan for work rather than - * retry/block upon contention.) - * - * 3. Selection control. We maintain policy of always choosing to - * run local tasks rather than stealing, and always trying to - * steal tasks before trying to run a new submission. All steals - * are currently performed in randomly-chosen deq-order. It may be - * worthwhile to bias these with locality / anti-locality - * information, but doing this well probably requires more - * lower-level information from JVMs than currently provided. + * queues are initialized after starting. All together, these + * low-level implementation choices produce as much as a factor of + * 4 performance improvement compared to naive implementations, + * and enable the processing of billions of tasks per second, + * sometimes at the expense of ugliness. */ + /** + * Generator for initial random seeds for random victim + * selection. This is used only to create initial seeds. Random + * steals use a cheaper xorshift generator per steal attempt. We + * expect only rare contention on seedGenerator, so just use a + * plain Random. + */ + private static final Random seedGenerator = new Random(); + + /** + * The maximum stolen->joining link depth allowed in helpJoinTask. + * Depths for legitimate chains are unbounded, but we use a fixed + * constant to avoid (otherwise unchecked) cycles and bound + * staleness of traversal parameters at the expense of sometimes + * blocking when we could be helping. + */ + private static final int MAX_HELP_DEPTH = 8; + /** * Capacity of work-stealing queue array upon initialization. - * Must be a power of two. Initial size must be at least 2, but is + * Must be a power of two. Initial size must be at least 4, but is * padded to minimize cache effects. */ private static final int INITIAL_QUEUE_CAPACITY = 1 << 13; /** * Maximum work-stealing queue array size. Must be less than or - * equal to 1 << 28 to ensure lack of index wraparound. (This - * is less than usual bounds, because we need leftshift by 3 - * to be in int range). + * equal to 1 << (31 - width of array entry) to ensure lack of + * index wraparound. The value is set in the static block + * at the end of this file after obtaining width. */ - private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 28; + private static final int MAXIMUM_QUEUE_CAPACITY; /** * The pool this thread works in. Accessed directly by ForkJoinTask. @@ -182,18 +212,10 @@ public class ForkJoinWorkerThread extends Thread { /** * The work-stealing queue array. Size must be a power of two. - * Initialized when thread starts, to improve memory locality. + * Initialized in onStart, to improve memory locality. */ private ForkJoinTask[] queue; - /** - * Index (mod queue.length) of next queue slot to push to or pop - * from. It is written only by owner thread, via ordered store. - * Both sp and base are allowed to wrap around on overflow, but - * (sp - base) still estimates size. - */ - private volatile int sp; - /** * Index (mod queue.length) of least valid queue slot, which is * always the next position to steal from if nonempty. @@ -201,46 +223,107 @@ public class ForkJoinWorkerThread extends Thread { private volatile int base; /** - * Activity status. When true, this worker is considered active. - * Must be false upon construction. It must be true when executing - * tasks, and BEFORE stealing a task. It must be false before - * calling pool.sync. + * Index (mod queue.length) of next queue slot to push to or pop + * from. It is written only by owner thread, and accessed by other + * threads only after reading (volatile) base. Both sp and base + * are allowed to wrap around on overflow, but (sp - base) still + * estimates size. */ - private boolean active; + private int sp; /** - * Run state of this worker. Supports simple versions of the usual - * shutdown/shutdownNow control. + * The index of most recent stealer, used as a hint to avoid + * traversal in method helpJoinTask. This is only a hint because a + * worker might have had multiple steals and this only holds one + * of them (usually the most current). Declared non-volatile, + * relying on other prevailing sync to keep reasonably current. */ - private volatile int runState; + private int stealHint; + + /** + * Run state of this worker. In addition to the usual run levels, + * tracks if this worker is suspended as a spare, and if it was + * killed (trimmed) while suspended. However, "active" status is + * maintained separately and modified only in conjunction with + * CASes of the pool's runState (which are currently sadly + * manually inlined for performance.) Accessed directly by pool + * to simplify checks for normal (zero) status. + */ + volatile int runState; + + private static final int TERMINATING = 0x01; + private static final int TERMINATED = 0x02; + private static final int SUSPENDED = 0x04; // inactive spare + private static final int TRIMMED = 0x08; // killed while suspended + + /** + * Number of steals. Directly accessed (and reset) by + * pool.tryAccumulateStealCount when idle. + */ + int stealCount; /** * Seed for random number generator for choosing steal victims. - * Uses Marsaglia xorshift. Must be nonzero upon initialization. + * Uses Marsaglia xorshift. Must be initialized as nonzero. */ private int seed; /** - * Number of steals, transferred to pool when idle + * Activity status. When true, this worker is considered active. + * Accessed directly by pool. Must be false upon construction. */ - private int stealCount; + boolean active; + + /** + * True if use local fifo, not default lifo, for local polling. + * Shadows value from ForkJoinPool. + */ + private final boolean locallyFifo; /** * Index of this worker in pool array. Set once by pool before - * running, and accessed directly by pool during cleanup etc. + * running, and accessed directly by pool to locate this worker in + * its workers array. */ int poolIndex; /** - * The last barrier event waited for. Accessed in pool callback - * methods, but only by current thread. + * The last pool event waited for. Accessed only by pool in + * callback methods invoked within this thread. */ - long lastEventCount; + int lastEventCount; /** - * True if use local fifo, not default lifo, for local polling + * Encoded index and event count of next event waiter. Accessed + * only by ForkJoinPool for managing event waiters. */ - private boolean locallyFifo; + volatile long nextWaiter; + + /** + * Number of times this thread suspended as spare. Accessed only + * by pool. + */ + int spareCount; + + /** + * Encoded index and count of next spare waiter. Accessed only + * by ForkJoinPool for managing spares. + */ + volatile int nextSpare; + + /** + * The task currently being joined, set only when actively trying + * to help other stealers in helpJoinTask. Written only by this + * thread, but read by others. + */ + private volatile ForkJoinTask currentJoin; + + /** + * The task most recently stolen from another worker (or + * submission queue). Written only by this thread, but read by + * others. + */ + private volatile ForkJoinTask currentSteal; /** * Creates a ForkJoinWorkerThread operating in the given pool. @@ -249,13 +332,24 @@ public class ForkJoinWorkerThread extends Thread { * @throws NullPointerException if pool is null */ protected ForkJoinWorkerThread(ForkJoinPool pool) { - if (pool == null) throw new NullPointerException(); this.pool = pool; - // Note: poolIndex is set by pool during construction - // Remaining initialization is deferred to onStart + this.locallyFifo = pool.locallyFifo; + setDaemon(true); + // To avoid exposing construction details to subclasses, + // remaining initialization is in start() and onStart() } - // Public access methods + /** + * Performs additional initialization and starts this thread. + */ + final void start(int poolIndex, UncaughtExceptionHandler ueh) { + this.poolIndex = poolIndex; + if (ueh != null) + setUncaughtExceptionHandler(ueh); + start(); + } + + // Public/protected methods /** * Returns the pool hosting this thread. @@ -279,130 +373,25 @@ public class ForkJoinWorkerThread extends Thread { return poolIndex; } - /** - * Establishes local first-in-first-out scheduling mode for forked - * tasks that are never joined. - * - * @param async if true, use locally FIFO scheduling - */ - void setAsyncMode(boolean async) { - locallyFifo = async; - } - - // Runstate management - - // Runstate values. Order matters - private static final int RUNNING = 0; - private static final int SHUTDOWN = 1; - private static final int TERMINATING = 2; - private static final int TERMINATED = 3; - - final boolean isShutdown() { return runState >= SHUTDOWN; } - final boolean isTerminating() { return runState >= TERMINATING; } - final boolean isTerminated() { return runState == TERMINATED; } - final boolean shutdown() { return transitionRunStateTo(SHUTDOWN); } - final boolean shutdownNow() { return transitionRunStateTo(TERMINATING); } - - /** - * Transitions to at least the given state. - * - * @return {@code true} if not already at least at given state - */ - private boolean transitionRunStateTo(int state) { - for (;;) { - int s = runState; - if (s >= state) - return false; - if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, state)) - return true; - } - } - - /** - * Tries to set status to active; fails on contention. - */ - private boolean tryActivate() { - if (!active) { - if (!pool.tryIncrementActiveCount()) - return false; - active = true; - } - return true; - } - - /** - * Tries to set status to inactive; fails on contention. - */ - private boolean tryInactivate() { - if (active) { - if (!pool.tryDecrementActiveCount()) - return false; - active = false; - } - return true; - } - - /** - * Computes next value for random victim probe. Scans don't - * require a very high quality generator, but also not a crummy - * one. Marsaglia xor-shift is cheap and works well. - */ - private static int xorShift(int r) { - r ^= (r << 13); - r ^= (r >>> 17); - return r ^ (r << 5); - } - - // Lifecycle methods - - /** - * This method is required to be public, but should never be - * called explicitly. It performs the main run loop to execute - * ForkJoinTasks. - */ - public void run() { - Throwable exception = null; - try { - onStart(); - pool.sync(this); // await first pool event - mainLoop(); - } catch (Throwable ex) { - exception = ex; - } finally { - onTermination(exception); - } - } - - /** - * Executes tasks until shut down. - */ - private void mainLoop() { - while (!isShutdown()) { - ForkJoinTask t = pollTask(); - if (t != null || (t = pollSubmission()) != null) - t.quietlyExec(); - else if (tryInactivate()) - pool.sync(this); - } - } - /** * Initializes internal state after construction but before * processing any tasks. If you override this method, you must - * invoke super.onStart() at the beginning of the method. + * invoke @code{super.onStart()} at the beginning of the method. * Initialization requires care: Most fields must have legal * default values, to ensure that attempted accesses from other * threads work correctly even before this thread starts * processing tasks. */ protected void onStart() { - // Allocate while starting to improve chances of thread-local - // isolation + int rs = seedGenerator.nextInt(); + seed = rs == 0? 1 : rs; // seed must be nonzero + + // Allocate name string and arrays in this thread + String pid = Integer.toString(pool.getPoolNumber()); + String wid = Integer.toString(poolIndex); + setName("ForkJoinPool-" + pid + "-worker-" + wid); + queue = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; - // Initial value of seed need not be especially random but - // should differ across workers and must be nonzero - int p = poolIndex + 1; - seed = p + (p << 8) + (p << 16) + (p << 24); // spread bits } /** @@ -414,97 +403,187 @@ public class ForkJoinWorkerThread extends Thread { * to an unrecoverable error, or {@code null} if completed normally */ protected void onTermination(Throwable exception) { - // Execute remaining local tasks unless aborting or terminating - while (exception == null && pool.isProcessingTasks() && base != sp) { - try { - ForkJoinTask t = popTask(); - if (t != null) - t.quietlyExec(); - } catch (Throwable ex) { - exception = ex; - } - } - // Cancel other tasks, transition status, notify pool, and - // propagate exception to uncaught exception handler try { - do {} while (!tryInactivate()); // ensure inactive + ForkJoinPool p = pool; + if (active) { + int a; // inline p.tryDecrementActiveCount + active = false; + do {} while (!UNSAFE.compareAndSwapInt + (p, poolRunStateOffset, a = p.runState, a - 1)); + } cancelTasks(); - runState = TERMINATED; - pool.workerTerminated(this); + setTerminated(); + p.workerTerminated(this); } catch (Throwable ex) { // Shouldn't ever happen if (exception == null) // but if so, at least rethrown exception = ex; } finally { if (exception != null) - ForkJoinTask.rethrowException(exception); + UNSAFE.throwException(exception); } } - // Intrinsics-based support for queue operations. - - private static long slotOffset(int i) { - return ((long) i << qShift) + qBase; - } - /** - * Adds in store-order the given task at given slot of q to null. - * Caller must ensure q is non-null and index is in range. + * This method is required to be public, but should never be + * called explicitly. It performs the main run loop to execute + * ForkJoinTasks. */ - private static void setSlot(ForkJoinTask[] q, int i, - ForkJoinTask t) { - UNSAFE.putOrderedObject(q, slotOffset(i), t); + public void run() { + Throwable exception = null; + try { + onStart(); + mainLoop(); + } catch (Throwable ex) { + exception = ex; + } finally { + onTermination(exception); + } } + // helpers for run() + /** - * CAS given slot of q to null. Caller must ensure q is non-null - * and index is in range. + * Finds and executes tasks, and checks status while running. */ - private static boolean casSlotNull(ForkJoinTask[] q, int i, - ForkJoinTask t) { - return UNSAFE.compareAndSwapObject(q, slotOffset(i), t, null); + private void mainLoop() { + boolean ran = false; // true if ran a task on last step + ForkJoinPool p = pool; + for (;;) { + p.preStep(this, ran); + if (runState != 0) + break; + ran = tryExecSteal() || tryExecSubmission(); + } } /** - * Sets sp in store-order. + * Tries to steal a task and execute it. + * + * @return true if ran a task */ - private void storeSp(int s) { - UNSAFE.putOrderedInt(this, spOffset, s); + private boolean tryExecSteal() { + ForkJoinTask t; + if ((t = scan()) != null) { + t.quietlyExec(); + UNSAFE.putOrderedObject(this, currentStealOffset, null); + if (sp != base) + execLocalTasks(); + return true; + } + return false; } - // Main queue methods + /** + * If a submission exists, try to activate and run it. + * + * @return true if ran a task + */ + private boolean tryExecSubmission() { + ForkJoinPool p = pool; + // This loop is needed in case attempt to activate fails, in + // which case we only retry if there still appears to be a + // submission. + while (p.hasQueuedSubmissions()) { + ForkJoinTask t; int a; + if (active || // inline p.tryIncrementActiveCount + (active = UNSAFE.compareAndSwapInt(p, poolRunStateOffset, + a = p.runState, a + 1))) { + if ((t = p.pollSubmission()) != null) { + UNSAFE.putOrderedObject(this, currentStealOffset, t); + t.quietlyExec(); + UNSAFE.putOrderedObject(this, currentStealOffset, null); + if (sp != base) + execLocalTasks(); + return true; + } + } + } + return false; + } /** - * Pushes a task. Called only by current thread. + * Runs local tasks until queue is empty or shut down. Call only + * while active. + */ + private void execLocalTasks() { + while (runState == 0) { + ForkJoinTask t = locallyFifo ? locallyDeqTask() : popTask(); + if (t != null) + t.quietlyExec(); + else if (sp == base) + break; + } + } + + /* + * Intrinsics-based atomic writes for queue slots. These are + * basically the same as methods in AtomicReferenceArray, but + * specialized for (1) ForkJoinTask elements (2) requirement that + * nullness and bounds checks have already been performed by + * callers and (3) effective offsets are known not to overflow + * from int to long (because of MAXIMUM_QUEUE_CAPACITY). We don't + * need corresponding version for reads: plain array reads are OK + * because they are protected by other volatile reads and are + * confirmed by CASes. + * + * Most uses don't actually call these methods, but instead contain + * inlined forms that enable more predictable optimization. We + * don't define the version of write used in pushTask at all, but + * instead inline there a store-fenced array slot write. + */ + + /** + * CASes slot i of array q from t to null. Caller must ensure q is + * non-null and index is in range. + */ + private static final boolean casSlotNull(ForkJoinTask[] q, int i, + ForkJoinTask t) { + return UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase, t, null); + } + + /** + * Performs a volatile write of the given task at given slot of + * array q. Caller must ensure q is non-null and index is in + * range. This method is used only during resets and backouts. + */ + private static final void writeSlot(ForkJoinTask[] q, int i, + ForkJoinTask t) { + UNSAFE.putObjectVolatile(q, (i << qShift) + qBase, t); + } + + // queue methods + + /** + * Pushes a task. Call only from this thread. * * @param t the task. Caller must ensure non-null. */ final void pushTask(ForkJoinTask t) { ForkJoinTask[] q = queue; - int mask = q.length - 1; - int s = sp; - setSlot(q, s & mask, t); - storeSp(++s); - if ((s -= base) == 1) - pool.signalWork(); - else if (s >= mask) - growQueue(); + int mask = q.length - 1; // implicit assert q != null + int s = sp++; // ok to increment sp before slot write + UNSAFE.putOrderedObject(q, ((s & mask) << qShift) + qBase, t); + if ((s -= base) == 0) + pool.signalWork(); // was empty + else if (s == mask) + growQueue(); // is full } /** * Tries to take a task from the base of the queue, failing if - * either empty or contended. + * empty or contended. Note: Specializations of this code appear + * in locallyDeqTask and elsewhere. * * @return a task, or null if none or contended */ final ForkJoinTask deqTask() { ForkJoinTask t; ForkJoinTask[] q; - int i; - int b; + int b, i; if (sp != (b = base) && (q = queue) != null && // must read q after b - (t = q[i = (q.length - 1) & b]) != null && - casSlotNull(q, i, t)) { + (t = q[i = (q.length - 1) & b]) != null && base == b && + UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase, t, null)) { base = b + 1; return t; } @@ -512,19 +591,20 @@ public class ForkJoinWorkerThread extends Thread { } /** - * Tries to take a task from the base of own queue, activating if - * necessary, failing only if empty. Called only by current thread. + * Tries to take a task from the base of own queue. Assumes active + * status. Called only by this thread. * * @return a task, or null if none */ final ForkJoinTask locallyDeqTask() { - int b; - while (sp != (b = base)) { - if (tryActivate()) { - ForkJoinTask[] q = queue; - int i = (q.length - 1) & b; - ForkJoinTask t = q[i]; - if (t != null && casSlotNull(q, i, t)) { + ForkJoinTask[] q = queue; + if (q != null) { + ForkJoinTask t; + int b, i; + while (sp != (b = base)) { + if ((t = q[i = (q.length - 1) & b]) != null && base == b && + UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase, + t, null)) { base = b + 1; return t; } @@ -534,46 +614,50 @@ public class ForkJoinWorkerThread extends Thread { } /** - * Returns a popped task, or null if empty. Ensures active status - * if non-null. Called only by current thread. + * Returns a popped task, or null if empty. Assumes active status. + * Called only by this thread. */ - final ForkJoinTask popTask() { - int s = sp; - while (s != base) { - if (tryActivate()) { - ForkJoinTask[] q = queue; - int mask = q.length - 1; - int i = (s - 1) & mask; + private ForkJoinTask popTask() { + ForkJoinTask[] q = queue; + if (q != null) { + int s; + while ((s = sp) != base) { + int i = (q.length - 1) & --s; + long u = (i << qShift) + qBase; // raw offset ForkJoinTask t = q[i]; - if (t == null || !casSlotNull(q, i, t)) + if (t == null) // lost to stealer break; - storeSp(s - 1); - return t; + if (UNSAFE.compareAndSwapObject(q, u, t, null)) { + sp = s; // putOrderedInt may encourage more timely write + // UNSAFE.putOrderedInt(this, spOffset, s); + return t; + } } } return null; } /** - * Specialized version of popTask to pop only if - * topmost element is the given task. Called only - * by current thread while active. + * Specialized version of popTask to pop only if topmost element + * is the given task. Called only by this thread while active. * * @param t the task. Caller must ensure non-null. */ final boolean unpushTask(ForkJoinTask t) { + int s; ForkJoinTask[] q = queue; - int mask = q.length - 1; - int s = sp - 1; - if (casSlotNull(q, s & mask, t)) { - storeSp(s); + if ((s = sp) != base && q != null && + UNSAFE.compareAndSwapObject + (q, (((q.length - 1) & --s) << qShift) + qBase, t, null)) { + sp = s; // putOrderedInt may encourage more timely write + // UNSAFE.putOrderedInt(this, spOffset, s); return true; } return false; } /** - * Returns next task or null if empty or contended + * Returns next task, or null if empty or contended. */ final ForkJoinTask peekTask() { ForkJoinTask[] q = queue; @@ -606,104 +690,209 @@ public class ForkJoinWorkerThread extends Thread { ForkJoinTask t = oldQ[oldIndex]; if (t != null && !casSlotNull(oldQ, oldIndex, t)) t = null; - setSlot(newQ, b & newMask, t); + writeSlot(newQ, b & newMask, t); } while (++b != bf); pool.signalWork(); } + /** + * Computes next value for random victim probe in scan(). Scans + * don't require a very high quality generator, but also not a + * crummy one. Marsaglia xor-shift is cheap and works well enough. + * Note: This is manually inlined in scan(). + */ + private static final int xorShift(int r) { + r ^= r << 13; + r ^= r >>> 17; + return r ^ (r << 5); + } + /** * Tries to steal a task from another worker. Starts at a random * index of workers array, and probes workers until finding one * with non-empty queue or finding that all are empty. It * randomly selects the first n probes. If these are empty, it - * resorts to a full circular traversal, which is necessary to - * accurately set active status by caller. Also restarts if pool - * events occurred since last scan, which forces refresh of - * workers array, in case barrier was associated with resize. + * resorts to a circular sweep, which is necessary to accurately + * set active status. (The circular sweep uses steps of + * approximately half the array size plus 1, to avoid bias + * stemming from leftmost packing of the array in ForkJoinPool.) * * This method must be both fast and quiet -- usually avoiding * memory accesses that could disrupt cache sharing etc other than - * those needed to check for and take tasks. This accounts for, - * among other things, updating random seed in place without - * storing it until exit. + * those needed to check for and take tasks (or to activate if not + * already active). This accounts for, among other things, + * updating random seed in place without storing it until exit. * * @return a task, or null if none found */ private ForkJoinTask scan() { - ForkJoinTask t = null; - int r = seed; // extract once to keep scan quiet - ForkJoinWorkerThread[] ws; // refreshed on outer loop - int mask; // must be power 2 minus 1 and > 0 - outer:do { - if ((ws = pool.workers) != null && (mask = ws.length - 1) > 0) { - int idx = r; - int probes = ~mask; // use random index while negative - for (;;) { - r = xorShift(r); // update random seed - ForkJoinWorkerThread v = ws[mask & idx]; - if (v == null || v.sp == v.base) { - if (probes <= mask) - idx = (probes++ < 0) ? r : (idx + 1); - else - break; - } - else if (!tryActivate() || (t = v.deqTask()) == null) - continue outer; // restart on contention - else - break outer; - } - } - } while (pool.hasNewSyncEvent(this)); // retry on pool events - seed = r; - return t; - } - - /** - * Gets and removes a local or stolen task. - * - * @return a task, if available - */ - final ForkJoinTask pollTask() { - ForkJoinTask t = locallyFifo ? locallyDeqTask() : popTask(); - if (t == null && (t = scan()) != null) - ++stealCount; - return t; - } - - /** - * Gets a local task. - * - * @return a task, if available - */ - final ForkJoinTask pollLocalTask() { - return locallyFifo ? locallyDeqTask() : popTask(); - } - - /** - * Returns a pool submission, if one exists, activating first. - * - * @return a submission, if available - */ - private ForkJoinTask pollSubmission() { ForkJoinPool p = pool; - while (p.hasQueuedSubmissions()) { - ForkJoinTask t; - if (tryActivate() && (t = p.pollSubmission()) != null) - return t; + ForkJoinWorkerThread[] ws; // worker array + int n; // upper bound of #workers + if ((ws = p.workers) != null && (n = ws.length) > 1) { + boolean canSteal = active; // shadow active status + int r = seed; // extract seed once + int mask = n - 1; + int j = -n; // loop counter + int k = r; // worker index, random if j < 0 + for (;;) { + ForkJoinWorkerThread v = ws[k & mask]; + r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // inline xorshift + ForkJoinTask[] q; ForkJoinTask t; int b, a; + if (v != null && (b = v.base) != v.sp && + (q = v.queue) != null) { + int i = (q.length - 1) & b; + long u = (i << qShift) + qBase; // raw offset + int pid = poolIndex; + if ((t = q[i]) != null) { + if (!canSteal && // inline p.tryIncrementActiveCount + UNSAFE.compareAndSwapInt(p, poolRunStateOffset, + a = p.runState, a + 1)) + canSteal = active = true; + if (canSteal && v.base == b++ && + UNSAFE.compareAndSwapObject(q, u, t, null)) { + v.base = b; + v.stealHint = pid; + UNSAFE.putOrderedObject(this, + currentStealOffset, t); + seed = r; + ++stealCount; + return t; + } + } + j = -n; + k = r; // restart on contention + } + else if (++j <= 0) + k = r; + else if (j <= n) + k += (n >>> 1) | 1; + else + break; + } } return null; } - // Methods accessed only by Pool + // Run State management + + // status check methods used mainly by ForkJoinPool + final boolean isRunning() { return runState == 0; } + final boolean isTerminating() { return (runState & TERMINATING) != 0; } + final boolean isTerminated() { return (runState & TERMINATED) != 0; } + final boolean isSuspended() { return (runState & SUSPENDED) != 0; } + final boolean isTrimmed() { return (runState & TRIMMED) != 0; } + + /** + * Sets state to TERMINATING. Does NOT unpark or interrupt + * to wake up if currently blocked. Callers must do so if desired. + */ + final void shutdown() { + for (;;) { + int s = runState; + if ((s & (TERMINATING|TERMINATED)) != 0) + break; + if ((s & SUSPENDED) != 0) { // kill and wakeup if suspended + if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, + (s & ~SUSPENDED) | + (TRIMMED|TERMINATING))) + break; + } + else if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, + s | TERMINATING)) + break; + } + } + + /** + * Sets state to TERMINATED. Called only by onTermination(). + */ + private void setTerminated() { + int s; + do {} while (!UNSAFE.compareAndSwapInt(this, runStateOffset, + s = runState, + s | (TERMINATING|TERMINATED))); + } + + /** + * If suspended, tries to set status to unsuspended. + * Does NOT wake up if blocked. + * + * @return true if successful + */ + final boolean tryUnsuspend() { + int s; + while (((s = runState) & SUSPENDED) != 0) { + if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, + s & ~SUSPENDED)) + return true; + } + return false; + } + + /** + * Sets suspended status and blocks as spare until resumed + * or shutdown. + */ + final void suspendAsSpare() { + for (;;) { // set suspended unless terminating + int s = runState; + if ((s & TERMINATING) != 0) { // must kill + if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, + s | (TRIMMED | TERMINATING))) + return; + } + else if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, + s | SUSPENDED)) + break; + } + ForkJoinPool p = pool; + p.pushSpare(this); + while ((runState & SUSPENDED) != 0) { + if (p.tryAccumulateStealCount(this)) { + interrupted(); // clear/ignore interrupts + if ((runState & SUSPENDED) == 0) + break; + LockSupport.park(this); + } + } + } + + // Misc support methods for ForkJoinPool + + /** + * Returns an estimate of the number of tasks in the queue. Also + * used by ForkJoinTask. + */ + final int getQueueSize() { + int n; // external calls must read base first + return (n = -base + sp) <= 0 ? 0 : n; + } /** * Removes and cancels all tasks in queue. Can be called from any * thread. */ final void cancelTasks() { - ForkJoinTask t; - while (base != sp && (t = deqTask()) != null) - t.cancelIgnoringExceptions(); + ForkJoinTask cj = currentJoin; // try to cancel ongoing tasks + if (cj != null) { + currentJoin = null; + cj.cancelIgnoringExceptions(); + try { + this.interrupt(); // awaken wait + } catch (SecurityException ignore) { + } + } + ForkJoinTask cs = currentSteal; + if (cs != null) { + currentSteal = null; + cs.cancelIgnoringExceptions(); + } + while (base != sp) { + ForkJoinTask t = deqTask(); + if (t != null) + t.cancelIgnoringExceptions(); + } } /** @@ -713,87 +902,266 @@ public class ForkJoinWorkerThread extends Thread { */ final int drainTasksTo(Collection> c) { int n = 0; - ForkJoinTask t; - while (base != sp && (t = deqTask()) != null) { - c.add(t); - ++n; - } - return n; - } - - /** - * Gets and clears steal count for accumulation by pool. Called - * only when known to be idle (in pool.sync and termination). - */ - final int getAndClearStealCount() { - int sc = stealCount; - stealCount = 0; - return sc; - } - - /** - * Returns {@code true} if at least one worker in the given array - * appears to have at least one queued task. - * - * @param ws array of workers - */ - static boolean hasQueuedTasks(ForkJoinWorkerThread[] ws) { - if (ws != null) { - int len = ws.length; - for (int j = 0; j < 2; ++j) { // need two passes for clean sweep - for (int i = 0; i < len; ++i) { - ForkJoinWorkerThread w = ws[i]; - if (w != null && w.sp != w.base) - return true; - } + while (base != sp) { + ForkJoinTask t = deqTask(); + if (t != null) { + c.add(t); + ++n; } } - return false; + return n; } // Support methods for ForkJoinTask /** - * Returns an estimate of the number of tasks in the queue. + * Gets and removes a local task. + * + * @return a task, if available */ - final int getQueueSize() { - // suppress momentarily negative values - return Math.max(0, sp - base); + final ForkJoinTask pollLocalTask() { + ForkJoinPool p = pool; + while (sp != base) { + int a; // inline p.tryIncrementActiveCount + if (active || + (active = UNSAFE.compareAndSwapInt(p, poolRunStateOffset, + a = p.runState, a + 1))) + return locallyFifo ? locallyDeqTask() : popTask(); + } + return null; } /** - * Returns an estimate of the number of tasks, offset by a - * function of number of idle workers. + * Gets and removes a local or stolen task. + * + * @return a task, if available */ - final int getEstimatedSurplusTaskCount() { - // The halving approximates weighting idle vs non-idle workers - return (sp - base) - (pool.getIdleThreadCount() >>> 1); - } - - /** - * Scans, returning early if joinMe done. - */ - final ForkJoinTask scanWhileJoining(ForkJoinTask joinMe) { - ForkJoinTask t = pollTask(); - if (t != null && joinMe.status < 0 && sp == base) { - pushTask(t); // unsteal if done and this task would be stealable - t = null; + final ForkJoinTask pollTask() { + ForkJoinTask t = pollLocalTask(); + if (t == null) { + t = scan(); + // cannot retain/track/help steal + UNSAFE.putOrderedObject(this, currentStealOffset, null); } return t; } + /** + * Possibly runs some tasks and/or blocks, until task is done. + * + * @param joinMe the task to join + */ + final void joinTask(ForkJoinTask joinMe) { + // currentJoin only written by this thread; only need ordered store + ForkJoinTask prevJoin = currentJoin; + UNSAFE.putOrderedObject(this, currentJoinOffset, joinMe); + if (sp != base) + localHelpJoinTask(joinMe); + if (joinMe.status >= 0) + pool.awaitJoin(joinMe, this); + UNSAFE.putOrderedObject(this, currentJoinOffset, prevJoin); + } + + /** + * Run tasks in local queue until given task is done. + * + * @param joinMe the task to join + */ + private void localHelpJoinTask(ForkJoinTask joinMe) { + int s; + ForkJoinTask[] q; + while (joinMe.status >= 0 && (s = sp) != base && (q = queue) != null) { + int i = (q.length - 1) & --s; + long u = (i << qShift) + qBase; // raw offset + ForkJoinTask t = q[i]; + if (t == null) // lost to a stealer + break; + if (UNSAFE.compareAndSwapObject(q, u, t, null)) { + /* + * This recheck (and similarly in helpJoinTask) + * handles cases where joinMe is independently + * cancelled or forced even though there is other work + * available. Back out of the pop by putting t back + * into slot before we commit by writing sp. + */ + if (joinMe.status < 0) { + UNSAFE.putObjectVolatile(q, u, t); + break; + } + sp = s; + // UNSAFE.putOrderedInt(this, spOffset, s); + t.quietlyExec(); + } + } + } + + /** + * Unless terminating, tries to locate and help perform tasks for + * a stealer of the given task, or in turn one of its stealers. + * Traces currentSteal->currentJoin links looking for a thread + * working on a descendant of the given task and with a non-empty + * queue to steal back and execute tasks from. + * + * The implementation is very branchy to cope with potential + * inconsistencies or loops encountering chains that are stale, + * unknown, or of length greater than MAX_HELP_DEPTH links. All + * of these cases are dealt with by just returning back to the + * caller, who is expected to retry if other join mechanisms also + * don't work out. + * + * @param joinMe the task to join + */ + final void helpJoinTask(ForkJoinTask joinMe) { + ForkJoinWorkerThread[] ws; + int n; + if (joinMe.status < 0) // already done + return; + if ((runState & TERMINATING) != 0) { // cancel if shutting down + joinMe.cancelIgnoringExceptions(); + return; + } + if ((ws = pool.workers) == null || (n = ws.length) <= 1) + return; // need at least 2 workers + + ForkJoinTask task = joinMe; // base of chain + ForkJoinWorkerThread thread = this; // thread with stolen task + for (int d = 0; d < MAX_HELP_DEPTH; ++d) { // chain length + // Try to find v, the stealer of task, by first using hint + ForkJoinWorkerThread v = ws[thread.stealHint & (n - 1)]; + if (v == null || v.currentSteal != task) { + for (int j = 0; ; ++j) { // search array + if (j < n) { + ForkJoinTask vs; + if ((v = ws[j]) != null && + (vs = v.currentSteal) != null) { + if (joinMe.status < 0 || task.status < 0) + return; // stale or done + if (vs == task) { + thread.stealHint = j; + break; // save hint for next time + } + } + } + else + return; // no stealer + } + } + for (;;) { // Try to help v, using specialized form of deqTask + if (joinMe.status < 0) + return; + int b = v.base; + ForkJoinTask[] q = v.queue; + if (b == v.sp || q == null) + break; + int i = (q.length - 1) & b; + long u = (i << qShift) + qBase; + ForkJoinTask t = q[i]; + int pid = poolIndex; + ForkJoinTask ps = currentSteal; + if (task.status < 0) + return; // stale or done + if (t != null && v.base == b++ && + UNSAFE.compareAndSwapObject(q, u, t, null)) { + if (joinMe.status < 0) { + UNSAFE.putObjectVolatile(q, u, t); + return; // back out on cancel + } + v.base = b; + v.stealHint = pid; + UNSAFE.putOrderedObject(this, currentStealOffset, t); + t.quietlyExec(); + UNSAFE.putOrderedObject(this, currentStealOffset, ps); + } + } + // Try to descend to find v's stealer + ForkJoinTask next = v.currentJoin; + if (task.status < 0 || next == null || next == task || + joinMe.status < 0) + return; + task = next; + thread = v; + } + } + + /** + * Implements ForkJoinTask.getSurplusQueuedTaskCount(). + * Returns an estimate of the number of tasks, offset by a + * function of number of idle workers. + * + * This method provides a cheap heuristic guide for task + * partitioning when programmers, frameworks, tools, or languages + * have little or no idea about task granularity. In essence by + * offering this method, we ask users only about tradeoffs in + * overhead vs expected throughput and its variance, rather than + * how finely to partition tasks. + * + * In a steady state strict (tree-structured) computation, each + * thread makes available for stealing enough tasks for other + * threads to remain active. Inductively, if all threads play by + * the same rules, each thread should make available only a + * constant number of tasks. + * + * The minimum useful constant is just 1. But using a value of 1 + * would require immediate replenishment upon each steal to + * maintain enough tasks, which is infeasible. Further, + * partitionings/granularities of offered tasks should minimize + * steal rates, which in general means that threads nearer the top + * of computation tree should generate more than those nearer the + * bottom. In perfect steady state, each thread is at + * approximately the same level of computation tree. However, + * producing extra tasks amortizes the uncertainty of progress and + * diffusion assumptions. + * + * So, users will want to use values larger, but not much larger + * than 1 to both smooth over transient shortages and hedge + * against uneven progress; as traded off against the cost of + * extra task overhead. We leave the user to pick a threshold + * value to compare with the results of this call to guide + * decisions, but recommend values such as 3. + * + * When all threads are active, it is on average OK to estimate + * surplus strictly locally. In steady-state, if one thread is + * maintaining say 2 surplus tasks, then so are others. So we can + * just use estimated queue length (although note that (sp - base) + * can be an overestimate because of stealers lagging increments + * of base). However, this strategy alone leads to serious + * mis-estimates in some non-steady-state conditions (ramp-up, + * ramp-down, other stalls). We can detect many of these by + * further considering the number of "idle" threads, that are + * known to have zero queued tasks, so compensate by a factor of + * (#idle/#active) threads. + */ + final int getEstimatedSurplusTaskCount() { + return sp - base - pool.idlePerActive(); + } + /** * Runs tasks until {@code pool.isQuiescent()}. */ final void helpQuiescePool() { + ForkJoinTask ps = currentSteal; // to restore below for (;;) { - ForkJoinTask t = pollTask(); - if (t != null) + ForkJoinTask t = pollLocalTask(); + if (t != null || (t = scan()) != null) t.quietlyExec(); - else if (tryInactivate() && pool.isQuiescent()) - break; + else { + ForkJoinPool p = pool; + int a; // to inline CASes + if (active) { + if (!UNSAFE.compareAndSwapInt + (p, poolRunStateOffset, a = p.runState, a - 1)) + continue; // retry later + active = false; // inactivate + UNSAFE.putOrderedObject(this, currentStealOffset, ps); + } + if (p.isQuiescent()) { + active = true; // re-activate + do {} while (!UNSAFE.compareAndSwapInt + (p, poolRunStateOffset, a = p.runState, a+1)); + return; + } + } } - do {} while (!tryActivate()); // re-activate on exit } // Unsafe mechanics @@ -803,15 +1171,23 @@ public class ForkJoinWorkerThread extends Thread { objectFieldOffset("sp", ForkJoinWorkerThread.class); private static final long runStateOffset = objectFieldOffset("runState", ForkJoinWorkerThread.class); - private static final long qBase; + private static final long currentJoinOffset = + objectFieldOffset("currentJoin", ForkJoinWorkerThread.class); + private static final long currentStealOffset = + objectFieldOffset("currentSteal", ForkJoinWorkerThread.class); + private static final long qBase = + UNSAFE.arrayBaseOffset(ForkJoinTask[].class); + private static final long poolRunStateOffset = // to inline CAS + objectFieldOffset("runState", ForkJoinPool.class); + private static final int qShift; static { - qBase = UNSAFE.arrayBaseOffset(ForkJoinTask[].class); int s = UNSAFE.arrayIndexScale(ForkJoinTask[].class); if ((s & (s-1)) != 0) throw new Error("data type scale not a power of two"); qShift = 31 - Integer.numberOfLeadingZeros(s); + MAXIMUM_QUEUE_CAPACITY = 1 << (31 - qShift); } private static long objectFieldOffset(String field, Class klazz) { diff --git a/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java b/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java index ae327cabf36..82bed929072 100644 --- a/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java +++ b/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -42,6 +42,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Queue; import java.util.concurrent.locks.LockSupport; + /** * An unbounded {@link TransferQueue} based on linked nodes. * This queue orders elements FIFO (first-in-first-out) with respect @@ -233,24 +234,6 @@ public class LinkedTransferQueue extends AbstractQueue * additional GC bookkeeping ("write barriers") that are sometimes * more costly than the writes themselves because of contention). * - * Removal of interior nodes (due to timed out or interrupted - * waits, or calls to remove(x) or Iterator.remove) can use a - * scheme roughly similar to that described in Scherer, Lea, and - * Scott's SynchronousQueue. Given a predecessor, we can unsplice - * any node except the (actual) tail of the queue. To avoid - * build-up of cancelled trailing nodes, upon a request to remove - * a trailing node, it is placed in field "cleanMe" to be - * unspliced upon the next call to unsplice any other node. - * Situations needing such mechanics are not common but do occur - * in practice; for example when an unbounded series of short - * timed calls to poll repeatedly time out but never otherwise - * fall off the list because of an untimed call to take at the - * front of the queue. Note that maintaining field cleanMe does - * not otherwise much impact garbage retention even if never - * cleared by some other call because the held node will - * eventually either directly or indirectly lead to a self-link - * once off the list. - * * *** Overview of implementation *** * * We use a threshold-based approach to updates, with a slack @@ -266,15 +249,10 @@ public class LinkedTransferQueue extends AbstractQueue * per-thread one available, but even ThreadLocalRandom is too * heavy for these purposes. * - * With such a small slack threshold value, it is rarely - * worthwhile to augment this with path short-circuiting; i.e., - * unsplicing nodes between head and the first unmatched node, or - * similarly for tail, rather than advancing head or tail - * proper. However, it is used (in awaitMatch) immediately before - * a waiting thread starts to block, as a final bit of helping at - * a point when contention with others is extremely unlikely - * (since if other threads that could release it are operating, - * then the current thread wouldn't be blocking). + * With such a small slack threshold value, it is not worthwhile + * to augment this with path short-circuiting (i.e., unsplicing + * interior nodes) except in the case of cancellation/removal (see + * below). * * We allow both the head and tail fields to be null before any * nodes are enqueued; initializing upon first append. This @@ -356,6 +334,70 @@ public class LinkedTransferQueue extends AbstractQueue * versa) compared to their predecessors receive additional * chained spins, reflecting longer paths typically required to * unblock threads during phase changes. + * + * + * ** Unlinking removed interior nodes ** + * + * In addition to minimizing garbage retention via self-linking + * described above, we also unlink removed interior nodes. These + * may arise due to timed out or interrupted waits, or calls to + * remove(x) or Iterator.remove. Normally, given a node that was + * at one time known to be the predecessor of some node s that is + * to be removed, we can unsplice s by CASing the next field of + * its predecessor if it still points to s (otherwise s must + * already have been removed or is now offlist). But there are two + * situations in which we cannot guarantee to make node s + * unreachable in this way: (1) If s is the trailing node of list + * (i.e., with null next), then it is pinned as the target node + * for appends, so can only be removed later after other nodes are + * appended. (2) We cannot necessarily unlink s given a + * predecessor node that is matched (including the case of being + * cancelled): the predecessor may already be unspliced, in which + * case some previous reachable node may still point to s. + * (For further explanation see Herlihy & Shavit "The Art of + * Multiprocessor Programming" chapter 9). Although, in both + * cases, we can rule out the need for further action if either s + * or its predecessor are (or can be made to be) at, or fall off + * from, the head of list. + * + * Without taking these into account, it would be possible for an + * unbounded number of supposedly removed nodes to remain + * reachable. Situations leading to such buildup are uncommon but + * can occur in practice; for example when a series of short timed + * calls to poll repeatedly time out but never otherwise fall off + * the list because of an untimed call to take at the front of the + * queue. + * + * When these cases arise, rather than always retraversing the + * entire list to find an actual predecessor to unlink (which + * won't help for case (1) anyway), we record a conservative + * estimate of possible unsplice failures (in "sweepVotes"). + * We trigger a full sweep when the estimate exceeds a threshold + * ("SWEEP_THRESHOLD") indicating the maximum number of estimated + * removal failures to tolerate before sweeping through, unlinking + * cancelled nodes that were not unlinked upon initial removal. + * We perform sweeps by the thread hitting threshold (rather than + * background threads or by spreading work to other threads) + * because in the main contexts in which removal occurs, the + * caller is already timed-out, cancelled, or performing a + * potentially O(n) operation (e.g. remove(x)), none of which are + * time-critical enough to warrant the overhead that alternatives + * would impose on other threads. + * + * Because the sweepVotes estimate is conservative, and because + * nodes become unlinked "naturally" as they fall off the head of + * the queue, and because we allow votes to accumulate even while + * sweeps are in progress, there are typically significantly fewer + * such nodes than estimated. Choice of a threshold value + * balances the likelihood of wasted effort and contention, versus + * providing a worst-case bound on retention of interior nodes in + * quiescent queues. The value defined below was chosen + * empirically to balance these under various timeout scenarios. + * + * Note that we cannot self-link unlinked interior nodes during + * sweeps. However, the associated garbage chains terminate when + * some successor ultimately falls off the head of the list and is + * self-linked. */ /** True if on multiprocessor */ @@ -381,12 +423,20 @@ public class LinkedTransferQueue extends AbstractQueue */ private static final int CHAINED_SPINS = FRONT_SPINS >>> 1; + /** + * The maximum number of estimated removal failures (sweepVotes) + * to tolerate before sweeping through the queue unlinking + * cancelled nodes that were not unlinked upon initial + * removal. See above for explanation. The value must be at least + * two to avoid useless sweeps when removing trailing nodes. + */ + static final int SWEEP_THRESHOLD = 32; + /** * Queue nodes. Uses Object, not E, for items to allow forgetting * them after use. Relies heavily on Unsafe mechanics to minimize - * unnecessary ordering constraints: Writes that intrinsically - * precede or follow CASes use simple relaxed forms. Other - * cleanups use releasing/lazy writes. + * unnecessary ordering constraints: Writes that are intrinsically + * ordered wrt other accesses or CASes use simple relaxed forms. */ static final class Node { final boolean isData; // false if this is a request node @@ -400,13 +450,13 @@ public class LinkedTransferQueue extends AbstractQueue } final boolean casItem(Object cmp, Object val) { - // assert cmp == null || cmp.getClass() != Node.class; + // assert cmp == null || cmp.getClass() != Node.class; return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); } /** - * Creates a new node. Uses relaxed write because item can only - * be seen if followed by CAS. + * Constructs a new node. Uses relaxed write because item can + * only be seen after publication via casNext. */ Node(Object item, boolean isData) { UNSAFE.putObject(this, itemOffset, item); // relaxed write @@ -422,13 +472,17 @@ public class LinkedTransferQueue extends AbstractQueue } /** - * Sets item to self (using a releasing/lazy write) and waiter - * to null, to avoid garbage retention after extracting or - * cancelling. + * Sets item to self and waiter to null, to avoid garbage + * retention after matching or cancelling. Uses relaxed writes + * because order is already constrained in the only calling + * contexts: item is forgotten only after volatile/atomic + * mechanics that extract items. Similarly, clearing waiter + * follows either CAS or return from park (if ever parked; + * else we don't care). */ final void forgetContents() { - UNSAFE.putOrderedObject(this, itemOffset, this); - UNSAFE.putOrderedObject(this, waiterOffset, null); + UNSAFE.putObject(this, itemOffset, this); + UNSAFE.putObject(this, waiterOffset, null); } /** @@ -462,7 +516,7 @@ public class LinkedTransferQueue extends AbstractQueue * Tries to artificially match a data node -- used by remove. */ final boolean tryMatchData() { - // assert isData; + // assert isData; Object x = item; if (x != null && x != this && casItem(x, null)) { LockSupport.unpark(waiter); @@ -486,12 +540,12 @@ public class LinkedTransferQueue extends AbstractQueue /** head of the queue; null until first enqueue */ transient volatile Node head; - /** predecessor of dangling unspliceable node */ - private transient volatile Node cleanMe; // decl here reduces contention - /** tail of the queue; null until first append */ private transient volatile Node tail; + /** The number of apparent failures to unsplice removed nodes */ + private transient volatile int sweepVotes; + // CAS methods for fields private boolean casTail(Node cmp, Node val) { return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); @@ -501,8 +555,8 @@ public class LinkedTransferQueue extends AbstractQueue return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); } - private boolean casCleanMe(Node cmp, Node val) { - return UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val); + private boolean casSweepVotes(int cmp, int val) { + return UNSAFE.compareAndSwapInt(this, sweepVotesOffset, cmp, val); } /* @@ -515,7 +569,7 @@ public class LinkedTransferQueue extends AbstractQueue @SuppressWarnings("unchecked") static E cast(Object item) { - // assert item == null || item.getClass() != Node.class; + // assert item == null || item.getClass() != Node.class; return (E) item; } @@ -544,10 +598,8 @@ public class LinkedTransferQueue extends AbstractQueue break; if (p.casItem(item, e)) { // match for (Node q = p; q != h;) { - Node n = q.next; // update head by 2 - if (n != null) // unless singleton - q = n; - if (head == h && casHead(h, q)) { + Node n = q.next; // update by 2 unless singleton + if (head == h && casHead(h, n == null? q : n)) { h.forgetNext(); break; } // advance and retry @@ -632,12 +684,12 @@ public class LinkedTransferQueue extends AbstractQueue for (;;) { Object item = s.item; if (item != e) { // matched - // assert item != s; + // assert item != s; s.forgetContents(); // avoid garbage return this.cast(item); } if ((w.isInterrupted() || (timed && nanos <= 0)) && - s.casItem(e, s)) { // cancel + s.casItem(e, s)) { // cancel unsplice(pred, s); return e; } @@ -647,9 +699,8 @@ public class LinkedTransferQueue extends AbstractQueue randomYields = ThreadLocalRandom.current(); } else if (spins > 0) { // spin - if (--spins == 0) - shortenHeadPath(); // reduce slack before blocking - else if (randomYields.nextInt(CHAINED_SPINS) == 0) + --spins; + if (randomYields.nextInt(CHAINED_SPINS) == 0) Thread.yield(); // occasionally yield } else if (s.waiter == null) { @@ -663,8 +714,6 @@ public class LinkedTransferQueue extends AbstractQueue } else { LockSupport.park(this); - s.waiter = null; - spins = -1; // spin if front upon wakeup } } } @@ -685,27 +734,6 @@ public class LinkedTransferQueue extends AbstractQueue return 0; } - /** - * Tries (once) to unsplice nodes between head and first unmatched - * or trailing node; failing on contention. - */ - private void shortenHeadPath() { - Node h, hn, p, q; - if ((p = h = head) != null && h.isMatched() && - (q = hn = h.next) != null) { - Node n; - while ((n = q.next) != q) { - if (n == null || !q.isMatched()) { - if (hn != q && h.next == hn) - h.casNext(hn, q); - break; - } - p = q; - q = n; - } - } - } - /* -------------- Traversal methods -------------- */ /** @@ -818,7 +846,8 @@ public class LinkedTransferQueue extends AbstractQueue public final void remove() { Node p = lastRet; if (p == null) throw new IllegalStateException(); - findAndRemoveDataNode(lastPred, p); + if (p.tryMatchData()) + unsplice(lastPred, p); } } @@ -828,99 +857,68 @@ public class LinkedTransferQueue extends AbstractQueue * Unsplices (now or later) the given deleted/cancelled node with * the given predecessor. * - * @param pred predecessor of node to be unspliced + * @param pred a node that was at one time known to be the + * predecessor of s, or null or s itself if s is/was at head * @param s the node to be unspliced */ - private void unsplice(Node pred, Node s) { - s.forgetContents(); // clear unneeded fields + final void unsplice(Node pred, Node s) { + s.forgetContents(); // forget unneeded fields /* - * At any given time, exactly one node on list cannot be - * unlinked -- the last inserted node. To accommodate this, if - * we cannot unlink s, we save its predecessor as "cleanMe", - * processing the previously saved version first. Because only - * one node in the list can have a null next, at least one of - * node s or the node previously saved can always be - * processed, so this always terminates. + * See above for rationale. Briefly: if pred still points to + * s, try to unlink s. If s cannot be unlinked, because it is + * trailing node or pred might be unlinked, and neither pred + * nor s are head or offlist, add to sweepVotes, and if enough + * votes have accumulated, sweep. */ - if (pred != null && pred != s) { - while (pred.next == s) { - Node oldpred = (cleanMe == null) ? null : reclean(); - Node n = s.next; - if (n != null) { - if (n != s) - pred.casNext(s, n); - break; + if (pred != null && pred != s && pred.next == s) { + Node n = s.next; + if (n == null || + (n != s && pred.casNext(s, n) && pred.isMatched())) { + for (;;) { // check if at, or could be, head + Node h = head; + if (h == pred || h == s || h == null) + return; // at head or list empty + if (!h.isMatched()) + break; + Node hn = h.next; + if (hn == null) + return; // now empty + if (hn != h && casHead(h, hn)) + h.forgetNext(); // advance head } - if (oldpred == pred || // Already saved - ((oldpred == null || oldpred.next == s) && - casCleanMe(oldpred, pred))) { - break; + if (pred.next != pred && s.next != s) { // recheck if offlist + for (;;) { // sweep now if enough votes + int v = sweepVotes; + if (v < SWEEP_THRESHOLD) { + if (casSweepVotes(v, v + 1)) + break; + } + else if (casSweepVotes(v, 0)) { + sweep(); + break; + } + } } } } } /** - * Tries to unsplice the deleted/cancelled node held in cleanMe - * that was previously uncleanable because it was at tail. - * - * @return current cleanMe node (or null) + * Unlinks matched (typically cancelled) nodes encountered in a + * traversal from head. */ - private Node reclean() { - /* - * cleanMe is, or at one time was, predecessor of a cancelled - * node s that was the tail so could not be unspliced. If it - * is no longer the tail, try to unsplice if necessary and - * make cleanMe slot available. This differs from similar - * code in unsplice() because we must check that pred still - * points to a matched node that can be unspliced -- if not, - * we can (must) clear cleanMe without unsplicing. This can - * loop only due to contention. - */ - Node pred; - while ((pred = cleanMe) != null) { - Node s = pred.next; - Node n; - if (s == null || s == pred || !s.isMatched()) - casCleanMe(pred, null); // already gone - else if ((n = s.next) != null) { - if (n != s) - pred.casNext(s, n); - casCleanMe(pred, null); - } - else + private void sweep() { + for (Node p = head, s, n; p != null && (s = p.next) != null; ) { + if (!s.isMatched()) + // Unmatched nodes are never self-linked + p = s; + else if ((n = s.next) == null) // trailing node is pinned break; - } - return pred; - } - - /** - * Main implementation of Iterator.remove(). Finds - * and unsplices the given data node. - * - * @param possiblePred possible predecessor of s - * @param s the node to remove - */ - final void findAndRemoveDataNode(Node possiblePred, Node s) { - // assert s.isData; - if (s.tryMatchData()) { - if (possiblePred != null && possiblePred.next == s) - unsplice(possiblePred, s); // was actual predecessor - else { - for (Node pred = null, p = head; p != null; ) { - if (p == s) { - unsplice(pred, p); - break; - } - if (p.isUnmatchedRequest()) - break; - pred = p; - if ((p = p.next) == pred) { // stale - pred = null; - p = head; - } - } - } + else if (s == n) // stale + // No need to also check for p == s, since that implies s == n + p = head; + else + p.casNext(s, n); } } @@ -1158,7 +1156,11 @@ public class LinkedTransferQueue extends AbstractQueue * @return {@code true} if this queue contains no elements */ public boolean isEmpty() { - return firstOfMode(true) == null; + for (Node p = head; p != null; p = succ(p)) { + if (!p.isMatched()) + return !p.isData; + } + return true; } public boolean hasWaitingConsumer() { @@ -1252,8 +1254,8 @@ public class LinkedTransferQueue extends AbstractQueue objectFieldOffset(UNSAFE, "head", LinkedTransferQueue.class); private static final long tailOffset = objectFieldOffset(UNSAFE, "tail", LinkedTransferQueue.class); - private static final long cleanMeOffset = - objectFieldOffset(UNSAFE, "cleanMe", LinkedTransferQueue.class); + private static final long sweepVotesOffset = + objectFieldOffset(UNSAFE, "sweepVotes", LinkedTransferQueue.class); static long objectFieldOffset(sun.misc.Unsafe UNSAFE, String field, Class klazz) { @@ -1266,5 +1268,4 @@ public class LinkedTransferQueue extends AbstractQueue throw error; } } - } diff --git a/jdk/src/share/classes/java/util/concurrent/Phaser.java b/jdk/src/share/classes/java/util/concurrent/Phaser.java index 7bf643cdfdb..623f46e41ed 100644 --- a/jdk/src/share/classes/java/util/concurrent/Phaser.java +++ b/jdk/src/share/classes/java/util/concurrent/Phaser.java @@ -898,7 +898,7 @@ public class Phaser { boolean doWait() { if (thread != null) { try { - ForkJoinPool.managedBlock(this, false); + ForkJoinPool.managedBlock(this); } catch (InterruptedException ie) { } } diff --git a/jdk/src/share/classes/java/util/spi/LocaleNameProvider.java b/jdk/src/share/classes/java/util/spi/LocaleNameProvider.java index b54195932e0..8c3639e171a 100644 --- a/jdk/src/share/classes/java/util/spi/LocaleNameProvider.java +++ b/jdk/src/share/classes/java/util/spi/LocaleNameProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,22 +44,23 @@ public abstract class LocaleNameProvider extends LocaleServiceProvider { } /** - * Returns a localized name for the given ISO 639 language code and the - * given locale that is appropriate for display to the user. + * Returns a localized name for the given + * IETF BCP47 language code and the given locale that is appropriate for + * display to the user. * For example, if languageCode is "fr" and locale * is en_US, getDisplayLanguage() will return "French"; if languageCode * is "en" and locale is fr_FR, getDisplayLanguage() will return "anglais". * If the name returned cannot be localized according to locale, * (say, the provider does not have a Japanese name for Croatian), * this method returns null. - * @param languageCode the ISO 639 language code string in the form of two + * @param languageCode the language code string in the form of two to eight * lower-case letters between 'a' (U+0061) and 'z' (U+007A) * @param locale the desired locale * @return the name of the given language code for the specified locale, or null if it's not * available. * @exception NullPointerException if languageCode or locale is null * @exception IllegalArgumentException if languageCode is not in the form of - * two lower-case letters, or locale isn't + * two or three lower-case letters, or locale isn't * one of the locales returned from * {@link java.util.spi.LocaleServiceProvider#getAvailableLocales() * getAvailableLocales()}. @@ -68,22 +69,52 @@ public abstract class LocaleNameProvider extends LocaleServiceProvider { public abstract String getDisplayLanguage(String languageCode, Locale locale); /** - * Returns a localized name for the given ISO 3166 country code and the - * given locale that is appropriate for display to the user. + * Returns a localized name for the given + * IETF BCP47 script code and the given locale that is appropriate for + * display to the user. + * For example, if scriptCode is "Latn" and locale + * is en_US, getDisplayScript() will return "Latin"; if scriptCode + * is "Cyrl" and locale is fr_FR, getDisplayScript() will return "cyrillique". + * If the name returned cannot be localized according to locale, + * (say, the provider does not have a Japanese name for Cyrillic), + * this method returns null. + * @param scriptCode the four letter script code string in the form of title-case + * letters (the first letter is upper-case character between 'A' (U+0041) and + * 'Z' (U+005A) followed by three lower-case character between 'a' (U+0061) + * and 'z' (U+007A)). + * @param locale the desired locale + * @return the name of the given script code for the specified locale, or null if it's not + * available. + * @exception NullPointerException if scriptCode or locale is null + * @exception IllegalArgumentException if scriptCode is not in the form of + * four title case letters, or locale isn't + * one of the locales returned from + * {@link java.util.spi.LocaleServiceProvider#getAvailableLocales() + * getAvailableLocales()}. + * @see java.util.Locale#getDisplayScript(java.util.Locale) + * @since 1.7 + */ + public abstract String getDisplayScript(String scriptCode, Locale locale); + + /** + * Returns a localized name for the given + * IETF BCP47 region code (either ISO 3166 country code or UN M.49 area + * codes) and the given locale that is appropriate for display to the user. * For example, if countryCode is "FR" and locale * is en_US, getDisplayCountry() will return "France"; if countryCode * is "US" and locale is fr_FR, getDisplayCountry() will return "Etats-Unis". * If the name returned cannot be localized according to locale, * (say, the provider does not have a Japanese name for Croatia), * this method returns null. - * @param countryCode the ISO 3166 country code string in the form of two - * upper-case letters between 'A' (U+0041) and 'Z' (U+005A) + * @param countryCode the country(region) code string in the form of two + * upper-case letters between 'A' (U+0041) and 'Z' (U+005A) or the UN M.49 area code + * in the form of three digit letters between '0' (U+0030) and '9' (U+0039). * @param locale the desired locale * @return the name of the given country code for the specified locale, or null if it's not * available. * @exception NullPointerException if countryCode or locale is null * @exception IllegalArgumentException if countryCode is not in the form of - * two upper-case letters, or locale isn't + * two upper-case letters or three digit letters, or locale isn't * one of the locales returned from * {@link java.util.spi.LocaleServiceProvider#getAvailableLocales() * getAvailableLocales()}. diff --git a/jdk/src/share/classes/java/util/spi/LocaleServiceProvider.java b/jdk/src/share/classes/java/util/spi/LocaleServiceProvider.java index 567e89271a8..02626e35e95 100644 --- a/jdk/src/share/classes/java/util/spi/LocaleServiceProvider.java +++ b/jdk/src/share/classes/java/util/spi/LocaleServiceProvider.java @@ -86,18 +86,19 @@ import java.util.Locale; * Otherwise, they call the getAvailableLocales() methods of * installed providers for the appropriate interface to find one that * supports the requested locale. If such a provider is found, its other - * methods are called to obtain the requested object or name. If neither - * the Java runtime environment itself nor an installed provider supports - * the requested locale, a fallback locale is constructed by replacing the - * first of the variant, country, or language strings of the locale that's - * not an empty string with an empty string, and the lookup process is - * restarted. In the case that the variant contains one or more '_'s, the - * fallback locale is constructed by replacing the variant with a new variant - * which eliminates the last '_' and the part following it. Even if a - * fallback occurs, methods that return requested objects or name are - * invoked with the original locale before the fallback.The Java runtime - * environment must support the root locale for all locale sensitive services - * in order to guarantee that this process terminates. + * methods are called to obtain the requested object or name. When checking + * whether a locale is supported, the locale's extensions are ignored. + * If neither the Java runtime environment itself nor an installed provider + * supports the requested locale, the methods go through a list of candidate + * locales and repeat the availability check for each until a match is found. + * The algorithm used for creating a list of candidate locales is same as + * the one used by ResourceBunlde by default (see + * {@link java.util.ResourceBundle.Control#getCandidateLocales getCandidateLocales} + * for the details). Even if a locale is resolved from the candidate list, + * methods that return requested objects or names are invoked with the original + * requested locale including extensions. The Java runtime environment must + * support the root locale for all locale sensitive services in order to + * guarantee that this process terminates. *

    * Providers of names (but not providers of other objects) are allowed to * return null for some name requests even for locales that they claim to @@ -124,6 +125,11 @@ public abstract class LocaleServiceProvider { /** * Returns an array of all locales for which this locale service provider * can provide localized objects or names. + *

    + * Note: Extensions in a Locale are ignored during + * service provider lookup. So the array returned by this method should + * not include two or more Locale objects only differing in + * their extensions. * * @return An array of all locales for which this locale service provider * can provide localized objects or names. diff --git a/jdk/src/share/classes/javax/sound/midi/MidiDevice.java b/jdk/src/share/classes/javax/sound/midi/MidiDevice.java index 0a8fed47855..1e9f225d943 100644 --- a/jdk/src/share/classes/javax/sound/midi/MidiDevice.java +++ b/jdk/src/share/classes/javax/sound/midi/MidiDevice.java @@ -204,6 +204,9 @@ public interface MidiDevice extends AutoCloseable { * MIDI data. The returned receiver must be closed when the application * has finished using it. * + *

    Usually the returned receiver implements + * the {@code MidiDeviceReceiver} interface. + * *

    Obtaining a Receiver with this method does not * open the device. To be able to use the device, it has to be * opened explicitly by calling {@link #open}. Also, closing the @@ -223,6 +226,10 @@ public interface MidiDevice extends AutoCloseable { * connected with this MidiDevice. * A receiver can be removed * from the device by closing it. + * + *

    Usually the returned receivers implement + * the {@code MidiDeviceReceiver} interface. + * * @return an unmodifiable list of the open receivers * @since 1.5 */ @@ -234,6 +241,9 @@ public interface MidiDevice extends AutoCloseable { * MIDI data The returned transmitter must be closed when the application * has finished using it. * + *

    Usually the returned transmitter implements + * the {@code MidiDeviceTransmitter} interface. + * *

    Obtaining a Transmitter with this method does not * open the device. To be able to use the device, it has to be * opened explicitly by calling {@link #open}. Also, closing the @@ -253,6 +263,10 @@ public interface MidiDevice extends AutoCloseable { * connected with this MidiDevice. * A transmitter can be removed * from the device by closing it. + * + *

    Usually the returned transmitters implement + * the {@code MidiDeviceTransmitter} interface. + * * @return an unmodifiable list of the open transmitters * @since 1.5 */ diff --git a/jdk/src/share/classes/com/sun/media/sound/MidiDeviceReceiver.java b/jdk/src/share/classes/javax/sound/midi/MidiDeviceReceiver.java similarity index 78% rename from jdk/src/share/classes/com/sun/media/sound/MidiDeviceReceiver.java rename to jdk/src/share/classes/javax/sound/midi/MidiDeviceReceiver.java index 9c76783db60..9ea1df7c38e 100644 --- a/jdk/src/share/classes/com/sun/media/sound/MidiDeviceReceiver.java +++ b/jdk/src/share/classes/javax/sound/midi/MidiDeviceReceiver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,20 +22,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.sun.media.sound; -import javax.sound.midi.MidiDevice; -import javax.sound.midi.Receiver; +package javax.sound.midi; /** - * A Receiver with reference to it's MidiDevice object. + *

    {@code MidiDeviceReceiver} is a {@code Receiver} which represents + * a MIDI input connector of a {@code MidiDevice} + * (see {@link MidiDevice#getReceiver()}). * - * @author Karl Helgason + * @since 1.7 */ public interface MidiDeviceReceiver extends Receiver { - - /** Obtains the MidiDevice object associated with this Receiver. + /** Obtains a MidiDevice object which is an owner of this Receiver. */ public MidiDevice getMidiDevice(); - } diff --git a/jdk/src/share/classes/javax/sound/midi/MidiDeviceTransmitter.java b/jdk/src/share/classes/javax/sound/midi/MidiDeviceTransmitter.java new file mode 100644 index 00000000000..b6a827188e2 --- /dev/null +++ b/jdk/src/share/classes/javax/sound/midi/MidiDeviceTransmitter.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.sound.midi; + + +/** + *

    {@code MidiDeviceTransmitter} is a {@code Transmitter} which represents + * a MIDI input connector of a {@code MidiDevice} + * (see {@link MidiDevice#getTransmitter()}). + * + * @since 1.7 + */ +public interface MidiDeviceTransmitter extends Transmitter { + + /** Obtains a MidiDevice object which is an owner of this Transmitter. + */ + public MidiDevice getMidiDevice(); +} diff --git a/jdk/src/share/classes/javax/sound/midi/MidiSystem.java b/jdk/src/share/classes/javax/sound/midi/MidiSystem.java index f865d92eb8a..8c0b5d9ebb5 100644 --- a/jdk/src/share/classes/javax/sound/midi/MidiSystem.java +++ b/jdk/src/share/classes/javax/sound/midi/MidiSystem.java @@ -47,6 +47,8 @@ import javax.sound.midi.spi.MidiDeviceProvider; import com.sun.media.sound.JDK13Services; import com.sun.media.sound.ReferenceCountingDevice; import com.sun.media.sound.AutoConnectSequencer; +import com.sun.media.sound.MidiDeviceReceiverEnvelope; +import com.sun.media.sound.MidiDeviceTransmitterEnvelope; /** @@ -225,6 +227,8 @@ public class MidiSystem { /** * Obtains a MIDI receiver from an external MIDI port * or other default device. + * The returned receiver always implements + * the {@code MidiDeviceReceiver} interface. * *

    If the system property * javax.sound.midi.Receiver @@ -261,6 +265,9 @@ public class MidiSystem { } else { receiver = device.getReceiver(); } + if (!(receiver instanceof MidiDeviceReceiver)) { + receiver = new MidiDeviceReceiverEnvelope(device, receiver); + } return receiver; } @@ -268,6 +275,8 @@ public class MidiSystem { /** * Obtains a MIDI transmitter from an external MIDI port * or other default source. + * The returned transmitter always implements + * the {@code MidiDeviceTransmitter} interface. * *

    If the system property * javax.sound.midi.Transmitter @@ -301,6 +310,9 @@ public class MidiSystem { } else { transmitter = device.getTransmitter(); } + if (!(transmitter instanceof MidiDeviceReceiver)) { + transmitter = new MidiDeviceTransmitterEnvelope(device, transmitter); + } return transmitter; } diff --git a/jdk/src/share/classes/javax/sound/sampled/AudioFormat.java b/jdk/src/share/classes/javax/sound/sampled/AudioFormat.java index 02f96577126..7457f8220eb 100644 --- a/jdk/src/share/classes/javax/sound/sampled/AudioFormat.java +++ b/jdk/src/share/classes/javax/sound/sampled/AudioFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -431,34 +431,36 @@ public class AudioFormat { /** - * Indicates whether this format matches the one specified. To match, - * two formats must have the same encoding, the same number of channels, - * and the same number of bits per sample and bytes per frame. - * The two formats must also have the same sample rate, - * unless the specified format has the sample rate value AudioSystem.NOT_SPECIFIED, - * which any sample rate will match. The frame rates must - * similarly be equal, unless the specified format has the frame rate - * value AudioSystem.NOT_SPECIFIED. The byte order (big-endian or little-endian) - * must match if the sample size is greater than one byte. + * Indicates whether this format matches the one specified. + * To match, two formats must have the same encoding, + * and consistent values of the number of channels, sample rate, sample size, + * frame rate, and frame size. + * The values of the property are consistent if they are equal + * or the specified format has the property value + * {@code AudioSystem.NOT_SPECIFIED}. + * The byte order (big-endian or little-endian) must be the same + * if the sample size is greater than one byte. * * @param format format to test for match - * @return true if this format matches the one specified, - * false otherwise. - */ - /* - * $$kk: 04.20.99: i changed the semantics of this. + * @return {@code true} if this format matches the one specified, + * {@code false} otherwise. */ public boolean matches(AudioFormat format) { - - if (format.getEncoding().equals(getEncoding()) && - ( (format.getSampleRate() == (float)AudioSystem.NOT_SPECIFIED) || (format.getSampleRate() == getSampleRate()) ) && - (format.getSampleSizeInBits() == getSampleSizeInBits()) && - (format.getChannels() == getChannels() && - (format.getFrameSize() == getFrameSize()) && - ( (format.getFrameRate() == (float)AudioSystem.NOT_SPECIFIED) || (format.getFrameRate() == getFrameRate()) ) && - ( (format.getSampleSizeInBits() <= 8) || (format.isBigEndian() == isBigEndian()) ) ) ) + if (format.getEncoding().equals(getEncoding()) + && (format.getChannels() == AudioSystem.NOT_SPECIFIED + || format.getChannels() == getChannels()) + && (format.getSampleRate() == (float)AudioSystem.NOT_SPECIFIED + || format.getSampleRate() == getSampleRate()) + && (format.getSampleSizeInBits() == AudioSystem.NOT_SPECIFIED + || format.getSampleSizeInBits() == getSampleSizeInBits()) + && (format.getFrameRate() == (float)AudioSystem.NOT_SPECIFIED + || format.getFrameRate() == getFrameRate()) + && (format.getFrameSize() == AudioSystem.NOT_SPECIFIED + || format.getFrameSize() == getFrameSize()) + && (getSampleSizeInBits() <= 8 + || format.isBigEndian() == isBigEndian())) { return true; - + } return false; } @@ -552,14 +554,14 @@ public class AudioFormat { * which is simply a linear (proportional) representation of the sound * waveform. With PCM, the number stored in each sample is proportional * to the instantaneous amplitude of the sound pressure at that point in - * time. The numbers are frequently signed or unsigned integers. + * time. The numbers may be signed or unsigned integers or floats. * Besides PCM, other encodings include mu-law and a-law, which are nonlinear * mappings of the sound amplitude that are often used for recording speech. *

    * You can use a predefined encoding by referring to one of the static * objects created by this class, such as PCM_SIGNED or * PCM_UNSIGNED. Service providers can create new encodings, such as - * compressed audio formats or floating-point PCM samples, and make + * compressed audio formats, and make * these available through the {@link AudioSystem} class. *

    * The Encoding class is static, so that all @@ -589,6 +591,13 @@ public class AudioFormat { */ public static final Encoding PCM_UNSIGNED = new Encoding("PCM_UNSIGNED"); + /** + * Specifies floating-point PCM data. + * + * @since 1.7 + */ + public static final Encoding PCM_FLOAT = new Encoding("PCM_FLOAT"); + /** * Specifies u-law encoded data. */ diff --git a/jdk/src/share/classes/javax/sql/CommonDataSource.java b/jdk/src/share/classes/javax/sql/CommonDataSource.java index 8d06bd63745..25b40686d87 100644 --- a/jdk/src/share/classes/javax/sql/CommonDataSource.java +++ b/jdk/src/share/classes/javax/sql/CommonDataSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,8 @@ package javax.sql; import java.sql.SQLException; import java.io.PrintWriter; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; /** * Interface that defines the methods which are common between DataSource, @@ -35,79 +37,93 @@ import java.io.PrintWriter; */ public interface CommonDataSource { - /** - *

    Retrieves the log writer for this DataSource - * object. - * - *

    The log writer is a character output stream to which all logging - * and tracing messages for this data source will be - * printed. This includes messages printed by the methods of this - * object, messages printed by methods of other objects manufactured - * by this object, and so on. Messages printed to a data source - * specific log writer are not printed to the log writer associated - * with the java.sql.DriverManager class. When a - * DataSource object is - * created, the log writer is initially null; in other words, the - * default is for logging to be disabled. - * - * @return the log writer for this data source or null if - * logging is disabled - * @exception java.sql.SQLException if a database access error occurs - * @see #setLogWriter - * @since 1.4 - */ - java.io.PrintWriter getLogWriter() throws SQLException; + /** + *

    Retrieves the log writer for this DataSource + * object. + * + *

    The log writer is a character output stream to which all logging + * and tracing messages for this data source will be + * printed. This includes messages printed by the methods of this + * object, messages printed by methods of other objects manufactured + * by this object, and so on. Messages printed to a data source + * specific log writer are not printed to the log writer associated + * with the java.sql.DriverManager class. When a + * DataSource object is + * created, the log writer is initially null; in other words, the + * default is for logging to be disabled. + * + * @return the log writer for this data source or null if + * logging is disabled + * @exception java.sql.SQLException if a database access error occurs + * @see #setLogWriter + * @since 1.4 + */ + java.io.PrintWriter getLogWriter() throws SQLException; - /** - *

    Sets the log writer for this DataSource - * object to the given java.io.PrintWriter object. - * - *

    The log writer is a character output stream to which all logging - * and tracing messages for this data source will be - * printed. This includes messages printed by the methods of this - * object, messages printed by methods of other objects manufactured - * by this object, and so on. Messages printed to a data source- - * specific log writer are not printed to the log writer associated - * with the java.sql.DriverManager class. When a - * DataSource object is created the log writer is - * initially null; in other words, the default is for logging to be - * disabled. - * - * @param out the new log writer; to disable logging, set to null - * @exception SQLException if a database access error occurs - * @see #getLogWriter - * @since 1.4 - */ - void setLogWriter(java.io.PrintWriter out) throws SQLException; + /** + *

    Sets the log writer for this DataSource + * object to the given java.io.PrintWriter object. + * + *

    The log writer is a character output stream to which all logging + * and tracing messages for this data source will be + * printed. This includes messages printed by the methods of this + * object, messages printed by methods of other objects manufactured + * by this object, and so on. Messages printed to a data source- + * specific log writer are not printed to the log writer associated + * with the java.sql.DriverManager class. When a + * DataSource object is created the log writer is + * initially null; in other words, the default is for logging to be + * disabled. + * + * @param out the new log writer; to disable logging, set to null + * @exception SQLException if a database access error occurs + * @see #getLogWriter + * @since 1.4 + */ + void setLogWriter(java.io.PrintWriter out) throws SQLException; - /** - *

    Sets the maximum time in seconds that this data source will wait - * while attempting to connect to a database. A value of zero - * specifies that the timeout is the default system timeout - * if there is one; otherwise, it specifies that there is no timeout. - * When a DataSource object is created, the login timeout is - * initially zero. - * - * @param seconds the data source login time limit - * @exception SQLException if a database access error occurs. - * @see #getLoginTimeout - * @since 1.4 - */ - void setLoginTimeout(int seconds) throws SQLException; + /** + *

    Sets the maximum time in seconds that this data source will wait + * while attempting to connect to a database. A value of zero + * specifies that the timeout is the default system timeout + * if there is one; otherwise, it specifies that there is no timeout. + * When a DataSource object is created, the login timeout is + * initially zero. + * + * @param seconds the data source login time limit + * @exception SQLException if a database access error occurs. + * @see #getLoginTimeout + * @since 1.4 + */ + void setLoginTimeout(int seconds) throws SQLException; - /** - * Gets the maximum time in seconds that this data source can wait - * while attempting to connect to a database. A value of zero - * means that the timeout is the default system timeout - * if there is one; otherwise, it means that there is no timeout. - * When a DataSource object is created, the login timeout is - * initially zero. - * - * @return the data source login time limit - * @exception SQLException if a database access error occurs. - * @see #setLoginTimeout - * @since 1.4 - */ - int getLoginTimeout() throws SQLException; + /** + * Gets the maximum time in seconds that this data source can wait + * while attempting to connect to a database. A value of zero + * means that the timeout is the default system timeout + * if there is one; otherwise, it means that there is no timeout. + * When a DataSource object is created, the login timeout is + * initially zero. + * + * @return the data source login time limit + * @exception SQLException if a database access error occurs. + * @see #setLoginTimeout + * @since 1.4 + */ + int getLoginTimeout() throws SQLException; + //------------------------- JDBC 4.1 ----------------------------------- + + /** + * Return the parent Logger of all the Loggers used by this data source. This + * should be the Logger farthest from the root Logger that is + * still an ancestor of all of the Loggers used by this data source. Configuring + * this Logger will affect all of the log messages generated by the data source. + * In the worst case, this may be the root Logger. + * + * @return the parent Logger for this data source + * @throws SQLFeatureNotSupportedException if the data source does not use java.util.logging. + * @since 1.7 + */ + public Logger getParentLogger() throws SQLFeatureNotSupportedException; } diff --git a/jdk/src/share/classes/javax/sql/rowset/CachedRowSet.java b/jdk/src/share/classes/javax/sql/rowset/CachedRowSet.java index c03d5534345..2a60bb3b7e7 100644 --- a/jdk/src/share/classes/javax/sql/rowset/CachedRowSet.java +++ b/jdk/src/share/classes/javax/sql/rowset/CachedRowSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -644,10 +644,10 @@ public interface CachedRowSet extends RowSet, Joinable { * of execute that takes a ResultSet object. * * @param data the ResultSet object containing the data - * to be read into this CachedRowSet object + * to be read into this CachedRowSet object * @throws SQLException if a null ResultSet object is supplied - * or this CachedRowSet object cannot - * retrieve the associated ResultSetMetaData object + * or this CachedRowSet object cannot + * retrieve the associated ResultSetMetaData object * @see #execute * @see java.sql.ResultSet * @see java.sql.ResultSetMetaData @@ -674,10 +674,10 @@ public interface CachedRowSet extends RowSet, Joinable { * to commit outstanding updates, those updates are lost. * * @param conn a standard JDBC Connection object with valid - * properties + * properties * @throws SQLException if an invalid Connection object is supplied - * or an error occurs in establishing the connection to the - * data source + * or an error occurs in establishing the connection to the + * data source * @see #populate * @see java.sql.Connection */ @@ -736,8 +736,8 @@ public interface CachedRowSet extends RowSet, Joinable { * * @throws SQLException if the cursor is on the insert row * @throws SyncProviderException if the underlying - * synchronization provider's writer fails to write the updates - * back to the data source + * synchronization provider's writer fails to write the updates + * back to the data source * @see #acceptChanges(java.sql.Connection) * @see javax.sql.RowSetWriter * @see javax.sql.rowset.spi.SyncFactory @@ -807,8 +807,8 @@ public interface CachedRowSet extends RowSet, Joinable { * @param con a standard JDBC Connection object * @throws SQLException if the cursor is on the insert row * @throws SyncProviderException if the underlying - * synchronization provider's writer fails to write the updates - * back to the data source + * synchronization provider's writer fails to write the updates + * back to the data source * @see #acceptChanges() * @see javax.sql.RowSetWriter * @see javax.sql.rowset.spi.SyncFactory @@ -867,7 +867,7 @@ public interface CachedRowSet extends RowSet, Joinable { * the rowset's Java VM resources. * * @throws SQLException if an error occurs flushing the contents of this - * CachedRowSet object + * CachedRowSet object * @see javax.sql.RowSetListener#rowSetChanged * @see java.sql.ResultSet#close */ @@ -948,9 +948,9 @@ public interface CachedRowSet extends RowSet, Joinable { * * @param idx an int identifying the column to be checked for updates * @return true if the designated column has been visibly updated; - * false otherwise + * false otherwise * @throws SQLException if the cursor is on the insert row, before the first row, - * or after the last row + * or after the last row * @see java.sql.DatabaseMetaData#updatesAreDetected */ public boolean columnUpdated(int idx) throws SQLException; @@ -963,9 +963,9 @@ public interface CachedRowSet extends RowSet, Joinable { * @param columnName a String object giving the name of the * column to be checked for updates * @return true if the column has been visibly updated; - * false otherwise + * false otherwise * @throws SQLException if the cursor is on the insert row, before the first row, - * or after the last row + * or after the last row * @see java.sql.DatabaseMetaData#updatesAreDetected */ public boolean columnUpdated(String columnName) throws SQLException; @@ -1003,7 +1003,7 @@ public interface CachedRowSet extends RowSet, Joinable { *

    * * @return a Collection object that contains the values in - * each row in this CachedRowSet object + * each row in this CachedRowSet object * @throws SQLException if an error occurs generating the collection * @see #toCollection(int) * @see #toCollection(String) @@ -1030,10 +1030,10 @@ public interface CachedRowSet extends RowSet, Joinable { * @param column an int indicating the column whose values * are to be represented in a Collection object * @return a Collection object that contains the values - * stored in the specified column of this CachedRowSet - * object + * stored in the specified column of this CachedRowSet + * object * @throws SQLException if an error occurs generating the collection or - * an invalid column id is provided + * an invalid column id is provided * @see #toCollection * @see #toCollection(String) */ @@ -1059,10 +1059,10 @@ public interface CachedRowSet extends RowSet, Joinable { * @param column a String object giving the name of the * column whose values are to be represented in a collection * @return a Collection object that contains the values - * stored in the specified column of this CachedRowSet - * object + * stored in the specified column of this CachedRowSet + * object * @throws SQLException if an error occurs generating the collection or - * an invalid column id is provided + * an invalid column id is provided * @see #toCollection * @see #toCollection(int) */ @@ -1100,7 +1100,7 @@ public interface CachedRowSet extends RowSet, Joinable { * @return the SyncProvider object that was set when the rowset * was instantiated, or if none was was set, the default provider * @throws SQLException if an error occurs while returning the - * SyncProvider object + * SyncProvider object * @see #setSyncProvider */ public SyncProvider getSyncProvider() throws SQLException; @@ -1127,7 +1127,7 @@ public interface CachedRowSet extends RowSet, Joinable { * @param provider a String object giving the fully qualified class * name of a SyncProvider implementation * @throws SQLException if an error occurs while attempting to reset the - * SyncProvider implementation + * SyncProvider implementation * @see #getSyncProvider */ public void setSyncProvider(String provider) throws SQLException; @@ -1152,9 +1152,9 @@ public interface CachedRowSet extends RowSet, Joinable { * object to the rowset. * * @param md a RowSetMetaData object containing - * metadata about the columns in this CachedRowSet object + * metadata about the columns in this CachedRowSet object * @throws SQLException if invalid metadata is supplied to the - * rowset + * rowset */ public void setMetaData(RowSetMetaData md) throws SQLException; @@ -1183,7 +1183,7 @@ public interface CachedRowSet extends RowSet, Joinable { * @return a ResultSet object that contains the original value for * this CachedRowSet object * @throws SQLException if an error occurs producing the - * ResultSet object + * ResultSet object */ public ResultSet getOriginal() throws SQLException; @@ -1217,7 +1217,7 @@ public interface CachedRowSet extends RowSet, Joinable { * A call to setOriginalRow is irreversible. * * @throws SQLException if there is no current row or an error is - * encountered resetting the contents of the original row + * encountered resetting the contents of the original row * @see #getOriginalRow */ public void setOriginalRow() throws SQLException; @@ -1326,7 +1326,7 @@ public interface CachedRowSet extends RowSet, Joinable { * as this CachedRowSet object and that has a cursor over * the same data * @throws SQLException if an error occurs or cloning is not - * supported in the underlying platform + * supported in the underlying platform * @see javax.sql.RowSetEvent * @see javax.sql.RowSetListener */ @@ -1344,10 +1344,10 @@ public interface CachedRowSet extends RowSet, Joinable { * established must be maintained. * * @return a new RowSet object that is a deep copy - * of this CachedRowSet object and is - * completely independent of this CachedRowSet object + * of this CachedRowSet object and is + * completely independent of this CachedRowSet object * @throws SQLException if an error occurs in generating the copy of - * the of this CachedRowSet object + * the of this CachedRowSet object * @see #createShared * @see #createCopySchema * @see #createCopyNoConstraints @@ -1396,10 +1396,10 @@ public interface CachedRowSet extends RowSet, Joinable { * in the copy. * * @return a new CachedRowSet object that is a deep copy - * of this CachedRowSet object and is - * completely independent of this CachedRowSet object + * of this CachedRowSet object and is + * completely independent of this CachedRowSet object * @throws SQLException if an error occurs in generating the copy of - * the of this CachedRowSet object + * the of this CachedRowSet object * @see #createCopy * @see #createShared * @see #createCopySchema @@ -1445,7 +1445,7 @@ public interface CachedRowSet extends RowSet, Joinable { * @return true if deleted rows are visible; * false otherwise * @throws SQLException if a rowset implementation is unable to - * to determine whether rows marked for deletion are visible + * to determine whether rows marked for deletion are visible * @see #setShowDeleted */ public boolean getShowDeleted() throws SQLException; @@ -1467,7 +1467,7 @@ public interface CachedRowSet extends RowSet, Joinable { * @param b true if deleted rows should be shown; * false otherwise * @exception SQLException if a rowset implementation is unable to - * to reset whether deleted rows should be visible + * to reset whether deleted rows should be visible * @see #getShowDeleted */ public void setShowDeleted(boolean b) throws SQLException; @@ -1523,9 +1523,12 @@ public interface CachedRowSet extends RowSet, Joinable { * set to false, the changes will not be committed until one of the * CachedRowSet interface transaction methods is called. * + * @deprecated Because this field is final (it is part of an interface), + * its value cannot be changed. * @see #commit * @see #rollback */ + @Deprecated public static final boolean COMMIT_ON_ACCEPT_CHANGES = true; /** @@ -1562,10 +1565,10 @@ public interface CachedRowSet extends RowSet, Joinable { * @param startRow the position in the ResultSet from where to start * populating the records in this CachedRowSet * @param rs the ResultSet object containing the data - * to be read into this CachedRowSet object + * to be read into this CachedRowSet object * @throws SQLException if a null ResultSet object is supplied - * or this CachedRowSet object cannot - * retrieve the associated ResultSetMetaData object + * or this CachedRowSet object cannot + * retrieve the associated ResultSetMetaData object * @see #execute * @see #populate(ResultSet) * @see java.sql.ResultSet @@ -1620,3 +1623,4 @@ public interface CachedRowSet extends RowSet, Joinable { public boolean previousPage() throws SQLException; } + diff --git a/jdk/src/share/classes/javax/sql/rowset/RowSetFactory.java b/jdk/src/share/classes/javax/sql/rowset/RowSetFactory.java new file mode 100644 index 00000000000..71d2ec531cf --- /dev/null +++ b/jdk/src/share/classes/javax/sql/rowset/RowSetFactory.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.sql.rowset; + +import java.sql.SQLException; + +/** + * An interface that defines the implementation of a factory that is used + * to obtain different types of {@code RowSet} implementations. + * + * @author Lance Andersen + * @since 1.7 + */ +public interface RowSetFactory{ + + /** + *

    Creates a new instance of a CachedRowSet.

    + * + * @return A new instance of a CachedRowSet. + * + * @throws SQLException if a CachedRowSet cannot + * be created. + * + * @since 1.7 + */ + public CachedRowSet createCachedRowSet() throws SQLException; + + /** + *

    Creates a new instance of a FilteredRowSet.

    + * + * @return A new instance of a FilteredRowSet. + * + * @throws SQLException if a FilteredRowSet cannot + * be created. + * + * @since 1.7 + */ + public FilteredRowSet createFilteredRowSet() throws SQLException; + + /** + *

    Creates a new instance of a JdbcRowSet.

    + * + * @return A new instance of a JdbcRowSet. + * + * @throws SQLException if a JdbcRowSet cannot + * be created. + * + * @since 1.7 + */ + public JdbcRowSet createJdbcRowSet() throws SQLException; + + /** + *

    Creates a new instance of a JoinRowSet.

    + * + * @return A new instance of a JoinRowSet. + * + * @throws SQLException if a JoinRowSet cannot + * be created. + * + * @since 1.7 + */ + public JoinRowSet createJoinRowSet() throws SQLException; + + /** + *

    Creates a new instance of a WebRowSet.

    + * + * @return A new instance of a WebRowSet. + * + * @throws SQLException if a WebRowSet cannot + * be created. + * + * @since 1.7 + */ + public WebRowSet createWebRowSet() throws SQLException; + +} \ No newline at end of file diff --git a/jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java b/jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java new file mode 100644 index 00000000000..1a84161ce15 --- /dev/null +++ b/jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.sql.rowset; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.sql.SQLException; +import java.util.ServiceLoader; +import javax.sql.rowset.RowSetFactory; + +/** + * A factory API that enables applications to obtain a + * {@code RowSetFactory} implementation that can be used to create different + * types of {@code RowSet} implementations. + *

    + * Example: + *

    + *
    + * RowSetFactory aFactory = RowSetProvider.newFactory();
    + * CachedRowSet crs = aFactory.createCachedRowSet();
    + * ...
    + * RowSetFactory rsf = RowSetProvider.newFactory("com.sun.rowset.RowSetFactoryImpl", null);
    + * WebRowSet wrs = rsf.createWebRowSet();
    + * 
    + *

    + * Tracing of this class may be enabled by setting the System property + * {@code javax.sql.rowset.RowSetFactory.debug} to any value but {@code false}. + *

    + * + * @author Lance Andersen + * @since 1.7 + */ +public class RowSetProvider { + + private static final String ROWSET_DEBUG_PROPERTY = "javax.sql.rowset.RowSetProvider.debug"; + private static final String ROWSET_FACTORY_IMPL = "com.sun.rowset.RowSetFactoryImpl"; + private static final String ROWSET_FACTORY_NAME = "javax.sql.rowset.RowSetFactory"; + /** + * Internal debug flag. + */ + private static boolean debug = true; + + + static { + // Check to see if the debug property is set + String val = getSystemProperty(ROWSET_DEBUG_PROPERTY); + // Allow simply setting the prop to turn on debug + debug = val != null && !"false".equals(val); + } + + + protected RowSetProvider () { + } + + /** + *

    Creates a new instance of a RowSetFactory + * implementation. This method uses the following + * look up order to determine + * the RowSetFactory implementation class to load:

    + *
      + *
    • + * The System property {@code javax.sql.rowset.RowsetFactory}. For example: + *
        + *
      • + * -Djavax.sql.rowset.RowsetFactory=com.sun.rowset.RowSetFactoryImpl + *
      • + *
      + *
    • + * The ServiceLocator API. The ServiceLocator API will look + * for a classname in the file + * {@code META-INF/services/javax.sql.rowset.RowSetFactory} + * in jars available to the runtime. For example, to have the the RowSetFactory + * implementation {@code com.sun.rowset.RowSetFactoryImpl } loaded, the + * entry in {@code META-INF/services/javax.sql.rowset.RowSetFactory} would be: + *
        + *
      • + * {@code com.sun.rowset.RowSetFactoryImpl } + *
      • + *
      + *
    • + *
    • + * Platform default RowSetFactory instance. + *
    • + *
    + * + *

    Once an application has obtained a reference to a {@code RowSetFactory}, + * it can use the factory to obtain RowSet instances.

    + * + * @return New instance of a RowSetFactory + * + * @throws SQLException if the default factory class cannot be loaded, + * instantiated. The cause will be set to actual Exception + * + * @see ServiceLoader + * @since 1.7 + */ + public static RowSetFactory newFactory() + throws SQLException { + // Use the system property first + RowSetFactory factory = null; + String factoryClassName = null; + try { + trace("Checking for Rowset System Property..."); + factoryClassName = getSystemProperty(ROWSET_FACTORY_NAME); + if (factoryClassName != null) { + trace("Found system property, value=" + factoryClassName); + factory = (RowSetFactory) getFactoryClass(factoryClassName, null, true).newInstance(); + } + } catch (ClassNotFoundException e) { + throw new SQLException( + "RowSetFactory: " + factoryClassName + " not found", e); + } catch (Exception e) { + throw new SQLException( + "RowSetFactory: " + factoryClassName + " could not be instantiated: " + e, + e); + } + + // Check to see if we found the RowSetFactory via a System property + if (factory == null) { + // If the RowSetFactory is not found via a System Property, now + // look it up via the ServiceLoader API and if not found, use the + // Java SE default. + factory = loadViaServiceLoader(); + factory = + factory == null ? newFactory(ROWSET_FACTORY_IMPL, null) : factory; + } + return (factory); + } + + /** + *

    Creates a new instance of a RowSetFactory from the + * specified factory class name. + * This function is useful when there are multiple providers in the classpath. + * It gives more control to the application as it can specify which provider + * should be loaded.

    + * + *

    Once an application has obtained a reference to a RowSetFactory + * it can use the factory to obtain RowSet instances.

    + * + * @param factoryClassName fully qualified factory class name that + * provides an implementation of javax.sql.rowset.RowSetFactory. + * + * @param cl ClassLoader used to load the factory + * class. If null current Thread's context + * classLoader is used to load the factory class. + * + * @return New instance of a RowSetFactory + * + * @throws SQLException if factoryClassName is + * null, or the factory class cannot be loaded, instantiated. + * + * @see #newFactory() + * + * @since 1.7 + */ + public static RowSetFactory newFactory(String factoryClassName, ClassLoader cl) + throws SQLException { + + trace("***In newInstance()"); + try { + Class providerClass = getFactoryClass(factoryClassName, cl, false); + RowSetFactory instance = (RowSetFactory) providerClass.newInstance(); + if (debug) { + trace("Created new instance of " + providerClass + + " using ClassLoader: " + cl); + } + return instance; + } catch (ClassNotFoundException x) { + throw new SQLException( + "Provider " + factoryClassName + " not found", x); + } catch (Exception x) { + throw new SQLException( + "Provider " + factoryClassName + " could not be instantiated: " + x, + x); + } + } + + /* + * Returns the class loader to be used. + * @return The ClassLoader to use. + * + */ + static private ClassLoader getContextClassLoader() throws SecurityException { + return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() { + + public Object run() { + ClassLoader cl = null; + + cl = Thread.currentThread().getContextClassLoader(); + + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + } + + return cl; + } + }); + } + + /** + * Attempt to load a class using the class loader supplied. If that fails + * and fall back is enabled, the current (i.e. bootstrap) class loader is + * tried. + * + * If the class loader supplied is null, first try using the + * context class loader followed by the current class loader. + * @return The class which was loaded + */ + static private Class getFactoryClass(String factoryClassName, ClassLoader cl, + boolean doFallback) throws ClassNotFoundException { + try { + if (cl == null) { + cl = getContextClassLoader(); + if (cl == null) { + throw new ClassNotFoundException(); + } else { + return cl.loadClass(factoryClassName); + } + } else { + return cl.loadClass(factoryClassName); + } + } catch (ClassNotFoundException e) { + if (doFallback) { + // Use current class loader + return Class.forName(factoryClassName, true, RowSetFactory.class.getClassLoader()); + } else { + throw e; + } + } + } + + /** + * Use the ServiceLoader mechanism to load the default RowSetFactory + * @return default RowSetFactory Implementation + */ + static private RowSetFactory loadViaServiceLoader() { + RowSetFactory theFactory = null; + trace("***in loadViaServiceLoader()"); + for (RowSetFactory factory : ServiceLoader.load(javax.sql.rowset.RowSetFactory.class)) { + trace(" Loading done by the java.util.ServiceLoader :" + factory.getClass().getName()); + theFactory = factory; + break; + } + return theFactory; + + } + + /** + * Returns the requested System Property. If a {@code SecurityException} + * occurs, just return NULL + * @param propName - System property to retreive + * @return The System property value or NULL if the property does not exist + * or a {@code SecurityException} occurs. + */ + static private String getSystemProperty(final String propName) { + String property = null; + try { + property = (String) AccessController.doPrivileged(new PrivilegedAction() { + + public Object run() { + return System.getProperty(propName); + } + }); + } catch (SecurityException se) { + if (debug) { + se.printStackTrace(); + } + } + return property; + } + + /** + * Debug routine which will output tracing if the System Property + * -Djavax.sql.rowset.RowSetFactory.debug is set + * @param msg - The debug message to display + */ + private static void trace(String msg) { + if (debug) { + System.err.println("###RowSets: " + msg); + } + } +} diff --git a/jdk/src/share/classes/javax/sql/rowset/package.html b/jdk/src/share/classes/javax/sql/rowset/package.html index 41d00d565b5..8b905cd63aa 100644 --- a/jdk/src/share/classes/javax/sql/rowset/package.html +++ b/jdk/src/share/classes/javax/sql/rowset/package.html @@ -5,7 +5,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/ClassCompare.java b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/ClassCompare.java new file mode 100644 index 00000000000..63a66f765d6 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/ClassCompare.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.tools.pack.verify; + +import java.io.*; +import java.util.*; +import java.util.jar.*; +import xmlkit.*; + +public class ClassCompare { + + /* + * @author ksrini + */ + private static XMLKit.Element getXMLelement(InputStream is, + boolean ignoreUnkAttrs, + List ignoreElements) throws IOException { + + ClassReader cr = new ClassReader(); + cr.keepOrder = false; + XMLKit.Element e = cr.readFrom(is); + + if (ignoreElements != null) { + XMLKit.Filter filter = XMLKit.elementFilter(ignoreElements); + e.removeAllInTree(filter); + } + + if (ignoreUnkAttrs == true) { + // This removes any unknown attributes + e.removeAllInTree(XMLKit.elementFilter("Attribute")); + } + return e; + } + + private static String getXMLPrettyString(XMLKit.Element e) throws IOException { + StringWriter out = new StringWriter(); + e.writePrettyTo(out); + return out.toString(); + } + + private static boolean compareClass0(JarFile jf1, JarFile jf2, + JarEntry je, boolean ignoreUnkAttrs, + List ignoreElements) + throws IOException { + + InputStream is1 = jf1.getInputStream(je); + InputStream is2 = jf2.getInputStream(je); + + // First we try to compare the bits if they are the same + boolean bCompare = JarFileCompare.compareStreams(is1, is2); + + // If they are the same there is nothing more to do. + if (bCompare) { + Globals.println("+++" + je.getName() + "+++\t" + + "b/b:PASS"); + return bCompare; + } + is1.close(); + is2.close(); + + is1 = jf1.getInputStream(je); + is2 = jf2.getInputStream(je); + + + XMLKit.Element e1 = getXMLelement(is1, ignoreUnkAttrs, ignoreElements); + XMLKit.Element e2 = getXMLelement(is2, ignoreUnkAttrs, ignoreElements); + + Globals.print("+++" + je.getName() + "+++\t" + + e1.size() + "/" + e1.size() + ":"); + + boolean result = true; + + if (e1.equals(e2)) { + Globals.println("PASS"); + } else { + Globals.println("FAIL"); + Globals.log("Strings differs"); + Globals.log(getXMLPrettyString(e1)); + Globals.log("----------"); + Globals.log(getXMLPrettyString(e2)); + result = false; + } + return result; + } + + /* + * Given two Class Paths could be jars the first being a reference + * will execute a series of comparisons on the classname specified + * The className could be null in which case it will iterate through + * all the classes, otherwise it will compare one class and exit. + */ + public static boolean compareClass(String jar1, String jar2, + String className, boolean ignoreUnkAttrs, + List ignoreElements) + throws IOException { + + Globals.println("Unknown attributes ignored:" + ignoreUnkAttrs); + if (ignoreElements != null) { + Globals.println(ignoreElements.toString()); + } + + JarFile jf1 = new JarFile(jar1); + JarFile jf2 = new JarFile(jar2); + + boolean result = true; + + if (className == null) { + for (JarEntry je1 : Collections.list((Enumeration) jf1.entries())) { + if (je1.getName().endsWith(".class")) { + JarEntry je2 = jf2.getJarEntry(je1.getName()); + boolean pf = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements); + if (result == true) { + result = pf; + } + } + } + } else { + JarEntry je1 = jf1.getJarEntry(className); + result = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements); + } + if (result == false) { + throw new RuntimeException("Class structural comparison failure"); + } + return result; + } + + public static boolean compareClass(String jar1, String jar2, + String className) throws IOException { + + Stack s = new Stack(); + if (Globals.ignoreDebugAttributes()) { + s = new Stack(); + s.push("LocalVariable"); + s.push("LocalVariableType"); + s.push("LineNumber"); + s.push("SourceFile"); + } + return compareClass(jar1, jar2, className, Globals.ignoreUnknownAttributes(), s); + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Globals.java b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Globals.java new file mode 100644 index 00000000000..2a51474bfde --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Globals.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * A collection of useful global utilities commonly used. + */ +package sun.tools.pack.verify; + +import java.io.*; +import java.util.*; + +/* + * @author ksrini + */ + +class Globals { + + private static int errors = 0; + private static PrintWriter _pw = null; + private static String _logFileName = null; + private static final String DEFAULT_LOG_FILE = "verifier.log"; + private static boolean _verbose = true; + private static boolean _ignoreJarDirectories = false; + private static boolean _checkJarClassOrdering = true; + private static boolean _bitWiseClassCompare = false; + // Ignore Deprecated, SourceFile and Synthetic + private static boolean _ignoreCompileAttributes = false; + // Ignore Debug Attributes LocalVariableTable, LocalVariableType,LineNumberTable + private static boolean _ignoreDebugAttributes = false; + private static boolean _ignoreUnknownAttributes = false; + private static boolean _validateClass = true; + private static Globals _instance = null; + + static Globals getInstance() { + if (_instance == null) { + _instance = new Globals(); + _verbose = (System.getProperty("sun.tools.pack.verify.verbose") == null) + ? false : true; + _ignoreJarDirectories = (System.getProperty("ignoreJarDirectories") == null) + ? false : true; + } + return _instance; + } + + static boolean ignoreCompileAttributes() { + return _ignoreCompileAttributes; + } + + static boolean ignoreDebugAttributes() { + return _ignoreDebugAttributes; + } + + static boolean ignoreUnknownAttributes() { + return _ignoreUnknownAttributes; + } + + static boolean ignoreJarDirectories() { + return _ignoreJarDirectories; + } + + static boolean validateClass() { + return _validateClass; + } + + static void setCheckJarClassOrdering(boolean flag) { + _checkJarClassOrdering = flag; + } + + static boolean checkJarClassOrdering() { + return _checkJarClassOrdering; + } + + static boolean bitWiseClassCompare() { + return _bitWiseClassCompare; + } + + static boolean setBitWiseClassCompare(boolean flag) { + return _bitWiseClassCompare = flag; + } + + public static boolean setIgnoreCompileAttributes(boolean flag) { + return _ignoreCompileAttributes = flag; + } + + static boolean setIgnoreDebugAttributes(boolean flag) { + return _ignoreDebugAttributes = flag; + } + + static boolean setIgnoreUnknownAttributes(boolean flag) { + return _ignoreUnknownAttributes = flag; + } + + static boolean setValidateClass(boolean flag) { + return _validateClass = flag; + } + + static int getErrors() { + return errors; + } + + static void trace(String s) { + if (_verbose) { + println(s); + } + } + + static void print(String s) { + _pw.print(s); + } + + static void println(String s) { + _pw.println(s); + } + + static void log(String s) { + errors++; + _pw.println("ERROR:" + s); + } + + static void lognoln(String s) { + errors++; + _pw.print(s); + } + + private static PrintWriter openFile(String fileName) { + //Lets create the directory if it does not exist. + File f = new File(fileName); + File baseDir = f.getParentFile(); + if (baseDir != null && baseDir.exists() == false) { + baseDir.mkdirs(); + } + try { + return new PrintWriter(new FileWriter(f), true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void closeFile() { + _pw.flush(); + _pw.close(); + } + + static void printPropsToLog() { + println("Log started " + new Date(System.currentTimeMillis())); + print(System.getProperty("java.vm.version")); + println("\t" + System.getProperty("java.vm.name")); + + println("System properties"); + println("\tjava.home=" + System.getProperty("java.home")); + println("\tjava.class.version=" + System.getProperty("java.class.version")); + println("\tjava.class.path=" + System.getProperty("java.class.path")); + println("\tjava.ext.dirs=" + System.getProperty("java.ext.dirs")); + println("\tos.name=" + System.getProperty("os.name")); + println("\tos.arch=" + System.getProperty("os.arch")); + println("\tos.version=" + System.getProperty("os.version")); + println("\tuser.name=" + System.getProperty("user.name")); + println("\tuser.home=" + System.getProperty("user.home")); + println("\tuser.dir=" + System.getProperty("user.dir")); + println("\tLocale.getDefault=" + Locale.getDefault()); + println("System properties end"); + } + + static void openLog(String s) { + _logFileName = (s != null) ? s : "." + File.separator + DEFAULT_LOG_FILE; + _logFileName = (new File(_logFileName).isDirectory()) + ? _logFileName + File.separator + DEFAULT_LOG_FILE : _logFileName; + _pw = openFile(_logFileName); + printPropsToLog(); + } + + static void closeLog() { + closeFile(); + } + + static String getLogFileName() { + return _logFileName; + } + + static void diffCharData(String s1, String s2) { + boolean diff = false; + char[] c1 = s1.toCharArray(); + char[] c2 = s2.toCharArray(); + if (c1.length != c2.length) { + diff = true; + Globals.log("Length differs: " + (c1.length - c2.length)); + } + // Take the smaller of the two arrays to prevent Array...Exception + int minlen = (c1.length < c2.length) ? c1.length : c2.length; + for (int i = 0; i < c1.length; i++) { + if (c1[i] != c2[i]) { + diff = true; + Globals.lognoln("\t idx[" + i + "] 0x" + Integer.toHexString(c1[i]) + "<>" + "0x" + Integer.toHexString(c2[i])); + Globals.log(" -> " + c1[i] + "<>" + c2[i]); + } + } + } + + static void diffByteData(String s1, String s2) { + boolean diff = false; + byte[] b1 = s1.getBytes(); + byte[] b2 = s2.getBytes(); + + if (b1.length != b2.length) { + diff = true; + //(+) b1 is greater, (-) b2 is greater + Globals.log("Length differs diff: " + (b1.length - b2.length)); + } + // Take the smaller of the two array to prevent Array...Exception + int minlen = (b1.length < b2.length) ? b1.length : b2.length; + for (int i = 0; i < b1.length; i++) { + if (b1[i] != b2[i]) { + diff = true; + Globals.log("\t" + "idx[" + i + "] 0x" + Integer.toHexString(b1[i]) + "<>" + "0x" + Integer.toHexString(b2[i])); + } + } + } + + static void dumpToHex(String s) { + try { + dumpToHex(s.getBytes("UTF-8")); + } catch (UnsupportedEncodingException uce) { + throw new RuntimeException(uce); + } + } + + static void dumpToHex(byte[] buffer) { + int linecount = 0; + byte[] b = new byte[16]; + for (int i = 0; i < buffer.length; i += 16) { + if (buffer.length - i > 16) { + System.arraycopy(buffer, i, b, 0, 16); + print16Bytes(b, linecount); + linecount += 16; + } else { + System.arraycopy(buffer, i, b, 0, buffer.length - i); + for (int n = buffer.length - (i + 1); n < 16; n++) { + b[n] = 0; + } + print16Bytes(b, linecount); + linecount += 16; + } + } + Globals.log("-----------------------------------------------------------------"); + } + + static void print16Bytes(byte[] buffer, int linecount) { + final int MAX = 4; + Globals.lognoln(paddedHexString(linecount, 4) + " "); + + for (int i = 0; i < buffer.length; i += 2) { + int iOut = pack2Bytes2Int(buffer[i], buffer[i + 1]); + Globals.lognoln(paddedHexString(iOut, 4) + " "); + } + + Globals.lognoln("| "); + + StringBuilder sb = new StringBuilder(new String(buffer)); + + for (int i = 0; i < buffer.length; i++) { + if (Character.isISOControl(sb.charAt(i))) { + sb.setCharAt(i, '.'); + } + } + Globals.log(sb.toString()); + } + + static int pack2Bytes2Int(byte b1, byte b2) { + int out = 0x0; + out += b1; + out <<= 8; + out &= 0x0000ffff; + out |= 0x000000ff & b2; + return out; + } + + static String paddedHexString(int n, int max) { + char[] c = Integer.toHexString(n).toCharArray(); + char[] out = new char[max]; + + for (int i = 0; i < max; i++) { + out[i] = '0'; + } + int offset = (max - c.length < 0) ? 0 : max - c.length; + for (int i = 0; i < c.length; i++) { + out[offset + i] = c[i]; + } + return new String(out); + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/JarFileCompare.java b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/JarFileCompare.java new file mode 100644 index 00000000000..419fda1ba23 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/JarFileCompare.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.tools.pack.verify; + +import java.io.*; +import java.util.*; +import java.util.jar.*; + +class JarFileCompare { + /* + * @author ksrini + */ + + private static VerifyTreeSet getVerifyTreeSet(String jarPath) { + VerifyTreeSet vts = new VerifyTreeSet(); + try { + JarFile j = new JarFile(jarPath); + for (JarEntry je : Collections.list((Enumeration) j.entries())) { + if (!je.isDirectory()) { // totally ignore directories + vts.add(je.getName()); + } + } + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + return vts; + } + + private static LinkedList getListOfClasses(String jarPath) { + LinkedList l = new LinkedList(); + try { + JarFile j = new JarFile(jarPath); + for (JarEntry je : Collections.list((Enumeration) j.entries())) { + if (!je.isDirectory() && je.getName().endsWith(".class")) { + l.add(je.getName()); + } + } + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + return l; + } + + private static void jarDirectoryCompare(String jarPath1, String jarPath2) { + VerifyTreeSet vts1 = getVerifyTreeSet(jarPath1); + VerifyTreeSet vts2 = getVerifyTreeSet(jarPath2); + + TreeSet diff1 = vts1.diff(vts2); + if (diff1.size() > 0) { + Globals.log("Left has the following entries that right does not have"); + Globals.log(diff1.toString()); + } + TreeSet diff2 = vts2.diff(vts1); + if (diff2.size() > 0) { + Globals.log("Right has the following entries that left does not have"); + Globals.log(diff2.toString()); + } + if (Globals.checkJarClassOrdering()) { + boolean error = false; + Globals.println("Checking Class Ordering"); + LinkedList l1 = getListOfClasses(jarPath1); + LinkedList l2 = getListOfClasses(jarPath2); + if (l1.size() != l2.size()) { + error = true; + Globals.log("The number of classes differs"); + Globals.log("\t" + l1.size() + "<>" + l2.size()); + } + for (int i = 0; i < l1.size(); i++) { + String s1 = (String) l1.get(i); + String s2 = (String) l2.get(i); + if (s1.compareTo(s2) != 0) { + error = true; + Globals.log("Ordering differs at[" + i + "] = " + s1); + Globals.log("\t" + s2); + } + } + } + } + + /* + * Returns true if the two Streams are bit identical, and false if they + * are not, no further diagnostics + */ + static boolean compareStreams(InputStream is1, InputStream is2) { + + BufferedInputStream bis1 = new BufferedInputStream(is1, 8192); + BufferedInputStream bis2 = new BufferedInputStream(is2, 8192); + try { + int i1, i2; + int count = 0; + while ((i1 = bis1.read()) == (i2 = bis2.read())) { + count++; + if (i1 < 0) { + // System.out.println("bytes read " + count); + return true; // got all the way to EOF + } + } + return false; // reads returned dif + + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + + private static void checkEntry(JarFile jf1, JarFile jf2, JarEntry je) throws IOException { + InputStream is1 = jf1.getInputStream(je); + InputStream is2 = jf2.getInputStream(je); + if (is1 != null && is2 != null) { + if (!compareStreams(jf1.getInputStream(je), jf2.getInputStream(je))) { + Globals.println("+++" + je.getName() + "+++"); + Globals.log("Error: File:" + je.getName() + + " differs, use a diff util for further diagnostics"); + } + } else { + Globals.println("+++" + je.getName() + "+++"); + Globals.log("Error: File:" + je.getName() + " not found in " + jf2.getName()); + } + } + + /* + * Given two jar files we compare and see if the jarfiles have all the + * entries. The property ignoreJarDirectories is set to true by default + * which means that Directory entries in a jar may be ignore. + */ + static void jarCompare(String jarPath1, String jarPath2) { + jarDirectoryCompare(jarPath1, jarPath2); + + try { + JarFile jf1 = new JarFile(jarPath1); + JarFile jf2 = new JarFile(jarPath2); + + int nclasses = 0; + int nentries = 0; + int entries_checked = 0; + int classes_checked = 0; + + for (JarEntry je : Collections.list((Enumeration) jf1.entries())) { + if (!je.isDirectory() && !je.getName().endsWith(".class")) { + nentries++; + } else if (je.getName().endsWith(".class")) { + nclasses++; + } + } + + for (JarEntry je : Collections.list((Enumeration) jf1.entries())) { + if (je.isDirectory()) { + continue; // Ignore directories + } + if (!je.getName().endsWith(".class")) { + entries_checked++; + if (je.getName().compareTo("META-INF/MANIFEST.MF") == 0) { + Manifest mf1 = new Manifest(jf1.getInputStream(je)); + Manifest mf2 = new Manifest(jf2.getInputStream(je)); + if (!mf1.equals(mf2)) { + Globals.log("Error: Manifests differ"); + Globals.log("Manifest1"); + Globals.log(mf1.getMainAttributes().entrySet().toString()); + Globals.log("Manifest2"); + Globals.log(mf2.getMainAttributes().entrySet().toString()); + } + } else { + checkEntry(jf1, jf2, je); + } + } else if (Globals.bitWiseClassCompare() == true) { + checkEntry(jf1, jf2, je); + classes_checked++; + } + } + if (Globals.bitWiseClassCompare()) { + Globals.println("Class entries checked (byte wise)/Total Class entries = " + + classes_checked + "/" + nclasses); + } + Globals.println("Non-class entries checked/Total non-class entries = " + + entries_checked + "/" + nentries); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Main.java b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Main.java new file mode 100644 index 00000000000..481c67b15ce --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Main.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +// The Main Entry point +package sun.tools.pack.verify; + +import java.io.*; + +/** + * This class provides a convenient entry point to the pack200 verifier. This + * compares two classes, either in path or in an archive. + * @see xmlkit.XMLKit + * @author ksrini + */ +public class Main { + + private static void syntax() { + System.out.println("Usage: "); + System.out.println("\tREFERENCE_CLASSPATH COMPARED_CLASSPATH [Options]"); + System.out.println("\tOptions:"); + System.out.println("\t\t-O check jar ordering"); + System.out.println("\t\t-C ignore compile attributes (Deprecated, SourceFile, Synthetic, )"); + System.out.println("\t\t-D ignore debug attributes (LocalVariable, LineNumber)"); + System.out.println("\t\t-u ignore unknown attributes"); + System.out.println("\t\t-V turn off class validation"); + System.out.println("\t\t-c CLASS, compare CLASS only"); + System.out.println("\t\t-b Compares all entries bitwise only"); + System.out.println("\t\t-l Directory or Log File Name"); + } + + /** + * main entry point to the class file comparator, which compares semantically + * class files in a classpath or an archive. + * @param args String array as described below + * @throws RuntimeException + *
    +     *  Usage:
    +     *     ReferenceClasspath SpecimenClaspath [Options]
    +     *     Options:
    +     *      -O check jar ordering
    +     *      -C do not compare compile attributes (Deprecated, SourceFile, Synthetic)
    +     *      -D do not compare debug attribute (LocalVariableTable, LineNumberTable)
    +     *      -u ignore unknown attributes
    +     *      -V turn off class validation
    +     *      -c class, compare a single class
    +     *      -b compares all entries bitwise (fastest)
    +     *      -l directory or log file name
    +     * 
    + */ + public static void main(String args[]) { + Globals.getInstance(); + if (args == null || args.length < 2) { + syntax(); + System.exit(1); + } + String refJarFileName = null; + String cmpJarFileName = null; + String specificClass = null; + String logDirFileName = null; + + for (int i = 0; i < args.length; i++) { + if (i == 0) { + refJarFileName = args[0]; + continue; + } + if (i == 1) { + cmpJarFileName = args[1]; + continue; + } + + if (args[i].startsWith("-O")) { + Globals.setCheckJarClassOrdering(true); + } + + if (args[i].startsWith("-b")) { + Globals.setBitWiseClassCompare(true); + } + + if (args[i].startsWith("-C")) { + Globals.setIgnoreCompileAttributes(true); + } + + if (args[i].startsWith("-D")) { + Globals.setIgnoreDebugAttributes(true); + } + + if (args[i].startsWith("-V")) { + Globals.setValidateClass(false); + } + + if (args[i].startsWith("-c")) { + i++; + specificClass = args[i].trim(); + } + + if (args[i].startsWith("-u")) { + i++; + Globals.setIgnoreUnknownAttributes(true); + } + + if (args[i].startsWith("-l")) { + i++; + logDirFileName = args[i].trim(); + } + } + + Globals.openLog(logDirFileName); + + File refJarFile = new File(refJarFileName); + File cmpJarFile = new File(cmpJarFileName); + + String f1 = refJarFile.getAbsoluteFile().toString(); + String f2 = cmpJarFile.getAbsoluteFile().toString(); + + System.out.println("LogFile:" + Globals.getLogFileName()); + System.out.println("Reference JAR:" + f1); + System.out.println("Compared JAR:" + f2); + + Globals.println("LogFile:" + Globals.getLogFileName()); + Globals.println("Reference JAR:" + f1); + Globals.println("Compared JAR:" + f2); + + Globals.println("Ignore Compile Attributes:" + Globals.ignoreCompileAttributes()); + Globals.println("Ignore Debug Attributes:" + Globals.ignoreDebugAttributes()); + Globals.println("Ignore Unknown Attributes:" + Globals.ignoreUnknownAttributes()); + Globals.println("Class ordering check:" + Globals.checkJarClassOrdering()); + Globals.println("Class validation check:" + Globals.validateClass()); + Globals.println("Bit-wise compare:" + Globals.bitWiseClassCompare()); + Globals.println("ClassName:" + ((specificClass == null) ? "ALL" : specificClass)); + + if (specificClass == null && Globals.bitWiseClassCompare() == true) { + JarFileCompare.jarCompare(refJarFileName, cmpJarFileName); + } else { + try { + ClassCompare.compareClass(refJarFileName, cmpJarFileName, specificClass); + } catch (Exception e) { + Globals.log("Exception " + e); + throw new RuntimeException(e); + } + } + + if (Globals.getErrors() > 0) { + System.out.println("FAIL"); + Globals.println("FAIL"); + System.exit(Globals.getErrors()); + } + + System.out.println("PASS"); + Globals.println("PASS"); + System.exit(Globals.getErrors()); + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/VerifyTreeSet.java b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/VerifyTreeSet.java new file mode 100644 index 00000000000..1e4c32b2af0 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/VerifyTreeSet.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.tools.pack.verify; + +import java.util.*; +/* + * @author ksrini + */ + +class VerifyTreeSet extends java.util.TreeSet { + + VerifyTreeSet() { + super(); + } + + public VerifyTreeSet(Comparator c) { + super(c); + } + + public TreeSet diff(TreeSet in) { + TreeSet delta = (TreeSet) this.clone(); + delta.removeAll(in); + return delta; + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java new file mode 100644 index 00000000000..4a3af66344e --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java @@ -0,0 +1,1003 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- + +import java.util.*; +import java.util.jar.*; +import java.lang.reflect.*; +import java.io.*; +import xmlkit.XMLKit.Element; + +/* + * @author jrose + */ +public class ClassReader extends ClassSyntax { + + private static final CommandLineParser CLP = new CommandLineParser("" + + "-source: +> = \n" + + "-dest: +> = \n" + + "-encoding: +> = \n" + + "-jcov $ \n -nojcov !-jcov \n" + + "-verbose $ \n -noverbose !-verbose \n" + + "-pretty $ \n -nopretty !-pretty \n" + + "-keepPath $ \n -nokeepPath !-keepPath \n" + + "-keepCP $ \n -nokeepCP !-keepCP \n" + + "-keepBytes $ \n -nokeepBytes !-keepBytes \n" + + "-parseBytes $ \n -noparseBytes !-parseBytes \n" + + "-resolveRefs $ \n -noresolveRefs !-resolveRefs \n" + + "-keepOrder $ \n -nokeepOrder !-keepOrder \n" + + "-keepSizes $ \n -nokeepSizes !-keepSizes \n" + + "-continue $ \n -nocontinue !-continue \n" + + "-attrDef & \n" + + "-@ >-@ . \n" + + "- +? \n" + + "\n"); + + public static void main(String[] ava) throws IOException { + ArrayList av = new ArrayList(Arrays.asList(ava)); + HashMap props = new HashMap(); + props.put("-encoding:", "UTF8"); // default + props.put("-keepOrder", null); // CLI default + props.put("-pretty", "1"); // CLI default + props.put("-continue", "1"); // CLI default + CLP.parse(av, props); + //System.out.println(props+" ++ "+av); + File source = asFile(props.get("-source:")); + File dest = asFile(props.get("-dest:")); + String encoding = props.get("-encoding:"); + boolean contError = props.containsKey("-continue"); + ClassReader options = new ClassReader(); + options.copyOptionsFrom(props); + /* + if (dest == null && av.size() > 1) { + dest = File.createTempFile("TestOut", ".dir", new File(".")); + dest.delete(); + if (!dest.mkdir()) + throw new RuntimeException("Cannot create "+dest); + System.out.println("Writing results to "+dest); + } + */ + if (av.isEmpty()) { + av.add("doit"); //to enter this loop + } + boolean readList = false; + for (String a : av) { + if (readList) { + readList = false; + InputStream fin; + if (a.equals("-")) { + fin = System.in; + } else { + fin = new FileInputStream(a); + } + + BufferedReader files = makeReader(fin, encoding); + for (String file; (file = files.readLine()) != null;) { + doFile(file, source, dest, options, encoding, contError); + } + if (fin != System.in) { + fin.close(); + } + } else if (a.equals("-@")) { + readList = true; + } else if (a.startsWith("-")) { + throw new RuntimeException("Bad flag argument: " + a); + } else if (source.getName().endsWith(".jar")) { + doJar(a, source, dest, options, encoding, contError); + } else { + doFile(a, source, dest, options, encoding, contError); + } + } + } + + private static File asFile(String str) { + return (str == null) ? null : new File(str); + } + + private static void doFile(String a, + File source, File dest, + ClassReader options, String encoding, + boolean contError) throws IOException { + if (!contError) { + doFile(a, source, dest, options, encoding); + } else { + try { + doFile(a, source, dest, options, encoding); + } catch (Exception ee) { + System.out.println("Error processing " + source + ": " + ee); + } + } + } + + private static void doJar(String a, File source, File dest, ClassReader options, + String encoding, Boolean contError) throws IOException { + try { + JarFile jf = new JarFile(source); + for (JarEntry je : Collections.list((Enumeration) jf.entries())) { + String name = je.getName(); + if (!name.endsWith(".class")) { + continue; + } + doStream(name, jf.getInputStream(je), dest, options, encoding); + } + } catch (IOException ioe) { + if (contError) { + System.out.println("Error processing " + source + ": " + ioe); + } else { + throw ioe; + } + } + } + + private static void doStream(String a, InputStream in, File dest, + ClassReader options, String encoding) throws IOException { + + File f = new File(a); + ClassReader cr = new ClassReader(options); + Element e = cr.readFrom(in); + + OutputStream out; + if (dest == null) { + //System.out.println(e.prettyString()); + out = System.out; + } else { + File outf = new File(dest, f.isAbsolute() ? f.getName() : f.getPath()); + String outName = outf.getName(); + File outSubdir = outf.getParentFile(); + outSubdir.mkdirs(); + int extPos = outName.lastIndexOf('.'); + if (extPos > 0) { + outf = new File(outSubdir, outName.substring(0, extPos) + ".xml"); + } + out = new FileOutputStream(outf); + } + + Writer outw = makeWriter(out, encoding); + if (options.pretty || !options.keepOrder) { + e.writePrettyTo(outw); + } else { + e.writeTo(outw); + } + if (out == System.out) { + outw.write("\n"); + outw.flush(); + } else { + outw.close(); + } + } + + private static void doFile(String a, + File source, File dest, + ClassReader options, String encoding) throws IOException { + File inf = new File(source, a); + if (dest != null && options.verbose) { + System.out.println("Reading " + inf); + } + + BufferedInputStream in = new BufferedInputStream(new FileInputStream(inf)); + + doStream(a, in, dest, options, encoding); + + } + + public static BufferedReader makeReader(InputStream in, String encoding) throws IOException { + // encoding in DEFAULT, '', UTF8, 8BIT, , or any valid encoding name + if (encoding.equals("8BIT")) { + encoding = EIGHT_BIT_CHAR_ENCODING; + } + if (encoding.equals("UTF8")) { + encoding = UTF8_ENCODING; + } + if (encoding.equals("DEFAULT")) { + encoding = null; + } + if (encoding.equals("-")) { + encoding = null; + } + Reader inw; + in = new BufferedInputStream(in); // add buffering + if (encoding == null) { + inw = new InputStreamReader(in); + } else { + inw = new InputStreamReader(in, encoding); + } + return new BufferedReader(inw); // add buffering + } + + public static Writer makeWriter(OutputStream out, String encoding) throws IOException { + // encoding in DEFAULT, '', UTF8, 8BIT, , or any valid encoding name + if (encoding.equals("8BIT")) { + encoding = EIGHT_BIT_CHAR_ENCODING; + } + if (encoding.equals("UTF8")) { + encoding = UTF8_ENCODING; + } + if (encoding.equals("DEFAULT")) { + encoding = null; + } + if (encoding.equals("-")) { + encoding = null; + } + Writer outw; + if (encoding == null) { + outw = new OutputStreamWriter(out); + } else { + outw = new OutputStreamWriter(out, encoding); + } + return new BufferedWriter(outw); // add buffering + } + + public Element result() { + return cfile; + } + protected InputStream in; + protected ByteArrayOutputStream buf = new ByteArrayOutputStream(1024); + protected byte cpTag[]; + protected String cpName[]; + protected String[] callables; // varies + public static final String REF_PREFIX = "#"; + // input options + public boolean pretty = false; + public boolean verbose = false; + public boolean keepPath = false; + public boolean keepCP = false; + public boolean keepBytes = false; + public boolean parseBytes = true; + public boolean resolveRefs = true; + public boolean keepOrder = true; + public boolean keepSizes = false; + + public ClassReader() { + super.cfile = new Element("ClassFile"); + } + + public ClassReader(ClassReader options) { + this(); + copyOptionsFrom(options); + } + + public void copyOptionsFrom(ClassReader options) { + pretty = options.pretty; + verbose = options.verbose; + keepPath = options.keepPath; + keepCP = options.keepCP; + keepBytes = options.keepBytes; + parseBytes = options.parseBytes; + resolveRefs = options.resolveRefs; + keepSizes = options.keepSizes; + keepOrder = options.keepOrder; + attrTypes = options.attrTypes; + } + + public void copyOptionsFrom(Map options) { + if (options.containsKey("-pretty")) { + pretty = (options.get("-pretty") != null); + } + if (options.containsKey("-verbose")) { + verbose = (options.get("-verbose") != null); + } + if (options.containsKey("-keepPath")) { + keepPath = (options.get("-keepPath") != null); + } + if (options.containsKey("-keepCP")) { + keepCP = (options.get("-keepCP") != null); + } + if (options.containsKey("-keepBytes")) { + keepBytes = (options.get("-keepBytes") != null); + } + if (options.containsKey("-parseBytes")) { + parseBytes = (options.get("-parseBytes") != null); + } + if (options.containsKey("-resolveRefs")) { + resolveRefs = (options.get("-resolveRefs") != null); + } + if (options.containsKey("-keepSizes")) { + keepSizes = (options.get("-keepSizes") != null); + } + if (options.containsKey("-keepOrder")) { + keepOrder = (options.get("-keepOrder") != null); + } + if (options.containsKey("-attrDef")) { + addAttrTypes(options.get("-attrDef").split(" ")); + } + if (options.get("-jcov") != null) { + addJcovAttrTypes(); + } + } + + public Element readFrom(InputStream in) throws IOException { + this.in = in; + // read the file header + int magic = u4(); + if (magic != 0xCAFEBABE) { + throw new RuntimeException("bad magic number " + Integer.toHexString(magic)); + } + cfile.setAttr("magic", "" + magic); + int minver = u2(); + int majver = u2(); + cfile.setAttr("minver", "" + minver); + cfile.setAttr("majver", "" + majver); + readCP(); + readClass(); + return result(); + } + + public Element readFrom(File file) throws IOException { + InputStream in = null; + try { + in = new FileInputStream(file); + Element e = readFrom(new BufferedInputStream(in)); + if (keepPath) { + e.setAttr("path", file.toString()); + } + return e; + } finally { + if (in != null) { + in.close(); + } + } + } + + private void readClass() throws IOException { + klass = new Element("Class"); + cfile.add(klass); + int flags = u2(); + String thisk = cpRef(); + String superk = cpRef(); + klass.setAttr("name", thisk); + boolean flagsSync = ((flags & Modifier.SYNCHRONIZED) != 0); + flags &= ~Modifier.SYNCHRONIZED; + String flagString = flagString(flags, klass); + if (!flagsSync) { + if (flagString.length() > 0) { + flagString += " "; + } + flagString += "!synchronized"; + } + klass.setAttr("flags", flagString); + klass.setAttr("super", superk); + for (int len = u2(), i = 0; i < len; i++) { + String interk = cpRef(); + klass.add(new Element("Interface", "name", interk)); + } + Element fields = readMembers("Field"); + klass.addAll(fields); + Element methods = readMembers("Method"); + if (!keepOrder) { + methods.sort(); + } + klass.addAll(methods); + readAttributesFor(klass); + klass.trimToSize(); + if (keepSizes) { + attachTo(cfile, formatAttrSizes()); + } + if (paddingSize != 0) { + cfile.setAttr("padding", "" + paddingSize); + } + } + + private Element readMembers(String kind) throws IOException { + int len = u2(); + Element members = new Element(len); + for (int i = 0; i < len; i++) { + Element member = new Element(kind); + int flags = u2(); + String name = cpRef(); + String type = cpRef(); + member.setAttr("name", name); + member.setAttr("type", type); + member.setAttr("flags", flagString(flags, member)); + readAttributesFor(member); + member.trimToSize(); + members.add(member); + } + return members; + } + + protected String flagString(int flags, Element holder) { + // Superset of Modifier.toString. + int kind = 0; + if (holder.getName() == "Field") { + kind = 1; + } + if (holder.getName() == "Method") { + kind = 2; + } + StringBuffer sb = new StringBuffer(); + for (int i = 0; flags != 0; i++, flags >>>= 1) { + if ((flags & 1) != 0) { + if (sb.length() > 0) { + sb.append(' '); + } + if (i < modifierNames.length) { + String[] names = modifierNames[i]; + String name = (kind < names.length) ? names[kind] : null; + for (String name2 : names) { + if (name != null) { + break; + } + name = name2; + } + sb.append(name); + } else { + sb.append("#").append(1 << i); + } + } + } + return sb.toString(); + } + + private void readAttributesFor(Element x) throws IOException { + Element prevCurrent; + Element y = new Element(); + if (x.getName() == "Code") { + prevCurrent = currentCode; + currentCode = x; + } else { + prevCurrent = currentMember; + currentMember = x; + } + for (int len = u2(), i = 0; i < len; i++) { + int ref = u2(); + String uname = cpName(ref).intern(); + String refName = uname; + if (!resolveRefs) { + refName = (REF_PREFIX + ref).intern(); + } + String qname = (x.getName() + "." + uname).intern(); + String wname = ("*." + uname).intern(); + String type = attrTypes.get(qname); + if (type == null || "".equals(type)) { + type = attrTypes.get(wname); + } + if ("".equals(type)) { + type = null; + } + int size = u4(); + int[] countVar = attrSizes.get(qname); + if (countVar == null) { + attrSizes.put(qname, countVar = new int[2]); + } + countVar[0] += 1; + countVar[1] += size; + buf.reset(); + for (int j = 0; j < size; j++) { + buf.write(u1()); + } + if (type == null && size == 0) { + y.add(new Element(uname)); // , etc. + } else if (type == null) { + //System.out.println("Warning: No attribute type description: "+qname); + // write cdata attribute + Element a = new Element("Attribute", + new String[]{"Name", refName}, + buf.toString(EIGHT_BIT_CHAR_ENCODING)); + a.addContent(getCPDigest()); + y.add(a); + } else if (type.equals("")) { + // ignore this attribute... + } else { + InputStream in0 = in; + int fileSize0 = fileSize; + ByteArrayInputStream in1 = new ByteArrayInputStream(buf.toByteArray()); + boolean ok = false; + try { + in = in1; + // parse according to type desc. + Element aval; + if (type.equals("...")) { + // delve into Code attribute + aval = readCode(); + } else if (type.equals("...")) { + // delve into StackMap attribute + aval = readStackMap(false); + } else if (type.equals("...")) { + // delve into StackMap attribute + aval = readStackMap(true); + } else if (type.startsWith("[")) { + aval = readAttributeCallables(type); + } else { + aval = readAttribute(type); + } + //System.out.println("attachTo 1 "+y+" <- "+aval); + attachTo(y, aval); + if (false + && in1.available() != 0) { + throw new RuntimeException("extra bytes in " + qname + " :" + in1.available()); + } + ok = true; + } finally { + in = in0; + fileSize = fileSize0; + if (!ok) { + System.out.println("*** Failed to read " + type); + } + } + } + } + if (x.getName() == "Code") { + currentCode = prevCurrent; + } else { + currentMember = prevCurrent; + } + if (!keepOrder) { + y.sort(); + y.sortAttrs(); + } + //System.out.println("attachTo 2 "+x+" <- "+y); + attachTo(x, y); + } + private int fileSize = 0; + private int paddingSize = 0; + private HashMap attrSizes = new HashMap(); + + private Element formatAttrSizes() { + Element e = new Element("Sizes"); + e.setAttr("fileSize", "" + fileSize); + for (Map.Entry ie : attrSizes.entrySet()) { + int[] countVar = ie.getValue(); + e.add(new Element("AttrSize", + "name", ie.getKey().toString(), + "count", "" + countVar[0], + "size", "" + countVar[1])); + } + return e; + } + + private void attachTo(Element x, Object aval0) { + if (aval0 == null) { + return; + } + //System.out.println("attachTo "+x+" : "+aval0); + if (!(aval0 instanceof Element)) { + x.add(aval0); + return; + } + Element aval = (Element) aval0; + if (!aval.isAnonymous()) { + x.add(aval); + return; + } + for (int imax = aval.attrSize(), i = 0; i < imax; i++) { + //%% + attachAttrTo(x, aval.getAttrName(i), aval.getAttr(i)); + } + x.addAll(aval); + } + + private void attachAttrTo(Element x, String aname, String aval) { + //System.out.println("attachAttrTo "+x+" : "+aname+"="+aval); + String aval0 = x.getAttr(aname); + if (aval0 != null) { + aval = aval0 + " " + aval; + } + x.setAttr(aname, aval); + } + + private Element readAttributeCallables(String type) throws IOException { + assert (callables == null); + callables = getBodies(type); + Element res = readAttribute(callables[0]); + callables = null; + return res; + } + + private Element readAttribute(String type) throws IOException { + //System.out.println("readAttribute "+type); + Element aval = new Element(); + String nextAttrName = null; + for (int len = type.length(), next, i = 0; i < len; i = next) { + String value; + switch (type.charAt(i)) { + case '<': + assert (nextAttrName == null); + next = type.indexOf('>', ++i); + String form = type.substring(i, next++); + if (form.indexOf('=') < 0) { + // elem_placement = '<' elemname '>' + assert (aval.attrSize() == 0); + assert (aval.isAnonymous()); + aval.setName(form.intern()); + } else { + // attr_placement = '<' attrname '=' (value)? '>' + int eqPos = form.indexOf('='); + nextAttrName = form.substring(0, eqPos).intern(); + if (eqPos != form.length() - 1) { + value = form.substring(eqPos + 1); + attachAttrTo(aval, nextAttrName, value); + nextAttrName = null; + } + // ...else subsequent type parsing will find the attr value + // and add it as "nextAttrName". + } + continue; + case '(': + next = type.indexOf(')', ++i); + int callee = Integer.parseInt(type.substring(i, next++)); + attachTo(aval, readAttribute(callables[callee])); + continue; + case 'N': // replication = 'N' int '[' type ... ']' + { + int count = getInt(type.charAt(i + 1), false); + assert (count >= 0); + next = i + 2; + String type1 = getBody(type, next); + next += type1.length() + 2; // skip body and brackets + for (int j = 0; j < count; j++) { + attachTo(aval, readAttribute(type1)); + } + } + continue; + case 'T': // union = 'T' any_int union_case* '(' ')' '[' body ']' + int tagValue; + if (type.charAt(++i) == 'S') { + tagValue = getInt(type.charAt(++i), true); + } else { + tagValue = getInt(type.charAt(i), false); + } + attachAttrTo(aval, "tag", "" + tagValue); // always named "tag" + ++i; // skip the int type char + // union_case = '(' uc_tag (',' uc_tag)* ')' '[' body ']' + // uc_tag = ('-')? digit+ + for (boolean foundCase = false;; i = next) { + assert (type.charAt(i) == '('); + next = type.indexOf(')', ++i); + assert (next >= i); + if (type.charAt(next - 1) == '\\' + && type.charAt(next - 2) != '\\') // Skip an escaped paren. + { + next = type.indexOf(')', next + 1); + } + String caseStr = type.substring(i, next++); + String type1 = getBody(type, next); + next += type1.length() + 2; // skip body and brackets + boolean lastCase = (caseStr.length() == 0); + if (!foundCase + && (lastCase || matchTag(tagValue, caseStr))) { + foundCase = true; + // Execute this body. + attachTo(aval, readAttribute(type1)); + } + if (lastCase) { + break; + } + } + continue; + case 'B': + case 'H': + case 'I': // int = oneof "BHI" + next = i + 1; + value = "" + getInt(type.charAt(i), false); + break; + case 'K': + assert ("IJFDLQ".indexOf(type.charAt(i + 1)) >= 0); + assert (type.charAt(i + 2) == 'H'); // only H works for now + next = i + 3; + value = cpRef(); + break; + case 'R': + assert ("CSDFMIU?".indexOf(type.charAt(i + 1)) >= 0); + assert (type.charAt(i + 2) == 'H'); // only H works for now + next = i + 3; + value = cpRef(); + break; + case 'P': // bci = 'P' int + next = i + 2; + value = "" + getInt(type.charAt(i + 1), false); + break; + case 'S': // signed_int = 'S' int + next = i + 2; + value = "" + getInt(type.charAt(i + 1), true); + break; + case 'F': + next = i + 2; + value = flagString(getInt(type.charAt(i + 1), false), currentMember); + break; + default: + throw new RuntimeException("bad attr format '" + type.charAt(i) + "': " + type); + } + // store the value + if (nextAttrName != null) { + attachAttrTo(aval, nextAttrName, value); + nextAttrName = null; + } else { + attachTo(aval, value); + } + } + //System.out.println("readAttribute => "+aval); + assert (nextAttrName == null); + return aval; + } + + private int getInt(char ch, boolean signed) throws IOException { + if (signed) { + switch (ch) { + case 'B': + return (byte) u1(); + case 'H': + return (short) u2(); + case 'I': + return (int) u4(); + } + } else { + switch (ch) { + case 'B': + return u1(); + case 'H': + return u2(); + case 'I': + return u4(); + } + } + assert ("BHIJ".indexOf(ch) >= 0); + return 0; + } + + private Element readCode() throws IOException { + int stack = u2(); + int local = u2(); + int length = u4(); + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; i++) { + sb.append((char) u1()); + } + String bytecodes = sb.toString(); + Element e = new Element("Code", + "stack", "" + stack, + "local", "" + local); + Element bytes = new Element("Bytes", (String[]) null, bytecodes); + if (keepBytes) { + e.add(bytes); + } + if (parseBytes) { + e.add(parseByteCodes(bytecodes)); + } + for (int len = u2(), i = 0; i < len; i++) { + int start = u2(); + int end = u2(); + int catsh = u2(); + String clasz = cpRef(); + e.add(new Element("Handler", + "start", "" + start, + "end", "" + end, + "catch", "" + catsh, + "class", clasz)); + } + readAttributesFor(e); + e.trimToSize(); + return e; + } + + private Element parseByteCodes(String bytecodes) { + Element e = InstructionSyntax.parse(bytecodes); + for (Element ins : e.elements()) { + Number ref = ins.getAttrNumber("ref"); + if (ref != null && resolveRefs) { + int id = ref.intValue(); + String val = cpName(id); + if (ins.getName().startsWith("ldc")) { + // Yuck: Arb. string cannot be an XML attribute. + ins.add(val); + val = ""; + byte tag = (id >= 0 && id < cpTag.length) ? cpTag[id] : 0; + if (tag != 0) { + ins.setAttrLong("tag", tag); + } + } + if (ins.getName() == "invokeinterface" + && computeInterfaceNum(val) == ins.getAttrLong("num")) { + ins.setAttr("num", null); // garbage bytes + } + ins.setAttr("ref", null); + ins.setAttr("val", val); + } + } + return e; + } + + private Element readStackMap(boolean hasXOption) throws IOException { + Element result = new Element(); + Element bytes = currentCode.findElement("Bytes"); + assert (bytes != null && bytes.size() == 1); + int byteLength = ((String) bytes.get(0)).length(); + boolean uoffsetIsU4 = (byteLength >= (1 << 16)); + boolean ulocalvarIsU4 = currentCode.getAttrLong("local") >= (1 << 16); + boolean ustackIsU4 = currentCode.getAttrLong("stack") >= (1 << 16); + if (hasXOption || uoffsetIsU4 || ulocalvarIsU4 || ustackIsU4) { + Element flags = new Element("StackMapFlags"); + if (hasXOption) { + flags.setAttr("hasXOption", "true"); + } + if (uoffsetIsU4) { + flags.setAttr("uoffsetIsU4", "true"); + } + if (ulocalvarIsU4) { + flags.setAttr("ulocalvarIsU4", "true"); + } + if (ustackIsU4) { + flags.setAttr("ustackIsU4", "true"); + } + currentCode.add(flags); + } + int frame_count = (uoffsetIsU4 ? u4() : u2()); + for (int i = 0; i < frame_count; i++) { + int bci = (uoffsetIsU4 ? u4() : u2()); + int flags = (hasXOption ? u1() : 0); + Element frame = new Element("Frame"); + result.add(frame); + if (flags != 0) { + frame.setAttr("flags", "" + flags); + } + frame.setAttr("bci", "" + bci); + // Scan local and stack types in this frame: + final int LOCALS = 0, STACK = 1; + for (int j = LOCALS; j <= STACK; j++) { + int typeSize; + if (j == LOCALS) { + typeSize = (ulocalvarIsU4 ? u4() : u2()); + } else { // STACK + typeSize = (ustackIsU4 ? u4() : u2()); + } + Element types = new Element(j == LOCALS ? "Local" : "Stack"); + for (int k = 0; k < typeSize; k++) { + int tag = u1(); + Element type = new Element(itemTagName(tag)); + types.add(type); + switch (tag) { + case ITEM_Object: + type.setAttr("class", cpRef()); + break; + case ITEM_Uninitialized: + case ITEM_ReturnAddress: + type.setAttr("bci", "" + (uoffsetIsU4 ? u4() : u2())); + break; + } + } + if (types.size() > 0) { + frame.add(types); + } + } + } + return result; + } + + private void readCP() throws IOException { + int cpLen = u2(); + cpTag = new byte[cpLen]; + cpName = new String[cpLen]; + int cpTem[][] = new int[cpLen][]; + for (int i = 1; i < cpLen; i++) { + cpTag[i] = (byte) u1(); + switch (cpTag[i]) { + case CONSTANT_Utf8: + buf.reset(); + for (int len = u2(), j = 0; j < len; j++) { + buf.write(u1()); + } + cpName[i] = buf.toString(UTF8_ENCODING); + break; + case CONSTANT_Integer: + cpName[i] = String.valueOf((int) u4()); + break; + case CONSTANT_Float: + cpName[i] = String.valueOf(Float.intBitsToFloat(u4())); + break; + case CONSTANT_Long: + cpName[i] = String.valueOf(u8()); + i += 1; + break; + case CONSTANT_Double: + cpName[i] = String.valueOf(Double.longBitsToDouble(u8())); + i += 1; + break; + case CONSTANT_Class: + case CONSTANT_String: + cpTem[i] = new int[]{u2()}; + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_NameAndType: + cpTem[i] = new int[]{u2(), u2()}; + break; + } + } + for (int i = 1; i < cpLen; i++) { + switch (cpTag[i]) { + case CONSTANT_Class: + case CONSTANT_String: + cpName[i] = cpName[cpTem[i][0]]; + break; + case CONSTANT_NameAndType: + cpName[i] = cpName[cpTem[i][0]] + " " + cpName[cpTem[i][1]]; + break; + } + } + // do fieldref et al after nameandtype are all resolved + for (int i = 1; i < cpLen; i++) { + switch (cpTag[i]) { + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + cpName[i] = cpName[cpTem[i][0]] + " " + cpName[cpTem[i][1]]; + break; + } + } + cpool = new Element("ConstantPool", cpName.length); + for (int i = 0; i < cpName.length; i++) { + if (cpName[i] == null) { + continue; + } + cpool.add(new Element(cpTagName(cpTag[i]), + new String[]{"id", "" + i}, + cpName[i])); + } + if (keepCP) { + cfile.add(cpool); + } + } + + private String cpRef() throws IOException { + int ref = u2(); + if (resolveRefs) { + return cpName(ref); + } else { + return REF_PREFIX + ref; + } + } + + private String cpName(int id) { + if (id >= 0 && id < cpName.length) { + return cpName[id]; + } else { + return "[CP#" + Integer.toHexString(id) + "]"; + } + } + + private long u8() throws IOException { + return ((long) u4() << 32) + (((long) u4() << 32) >>> 32); + } + + private int u4() throws IOException { + return (u2() << 16) + u2(); + } + + private int u2() throws IOException { + return (u1() << 8) + u1(); + } + + private int u1() throws IOException { + int x = in.read(); + if (x < 0) { + paddingSize++; + return 0; // error recovery + } + fileSize++; + assert (x == (x & 0xFF)); + return x; + } +} + diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java new file mode 100644 index 00000000000..d34ecbad004 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- +import xmlkit.XMLKit.*; + +import java.util.*; +import java.security.MessageDigest; +import java.nio.ByteBuffer; +import xmlkit.XMLKit.Element; +/* + * @author jrose + */ +public abstract class ClassSyntax { + + public interface GetCPIndex { + + int getCPIndex(int tag, String name); // cp finder + } + public static final int CONSTANT_Utf8 = 1, + CONSTANT_Integer = 3, + CONSTANT_Float = 4, + CONSTANT_Long = 5, + CONSTANT_Double = 6, + CONSTANT_Class = 7, + CONSTANT_String = 8, + CONSTANT_Fieldref = 9, + CONSTANT_Methodref = 10, + CONSTANT_InterfaceMethodref = 11, + CONSTANT_NameAndType = 12; + private static final String[] cpTagName = { + /* 0: */null, + /* 1: */ "Utf8", + /* 2: */ null, + /* 3: */ "Integer", + /* 4: */ "Float", + /* 5: */ "Long", + /* 6: */ "Double", + /* 7: */ "Class", + /* 8: */ "String", + /* 9: */ "Fieldref", + /* 10: */ "Methodref", + /* 11: */ "InterfaceMethodref", + /* 12: */ "NameAndType", + null + }; + private static final Set cpTagNames; + + static { + Set set = new HashSet(Arrays.asList(cpTagName)); + set.remove(null); + cpTagNames = Collections.unmodifiableSet(set); + } + public static final int ITEM_Top = 0, // replicates by [1..4,1..4] + ITEM_Integer = 1, // (ditto) + ITEM_Float = 2, + ITEM_Double = 3, + ITEM_Long = 4, + ITEM_Null = 5, + ITEM_UninitializedThis = 6, + ITEM_Object = 7, + ITEM_Uninitialized = 8, + ITEM_ReturnAddress = 9, + ITEM_LIMIT = 10; + private static final String[] itemTagName = { + "Top", + "Integer", + "Float", + "Double", + "Long", + "Null", + "UninitializedThis", + "Object", + "Uninitialized", + "ReturnAddress",}; + private static final Set itemTagNames; + + static { + Set set = new HashSet(Arrays.asList(itemTagName)); + set.remove(null); + itemTagNames = Collections.unmodifiableSet(set); + } + protected static final HashMap attrTypesBacking; + protected static final Map attrTypesInit; + + static { + HashMap at = new HashMap(); + + //at.put("*.Deprecated", ""); + //at.put("*.Synthetic", ""); + ////at.put("Field.ConstantValue", "KQH"); + //at.put("Class.SourceFile", "RUH"); + at.put("Method.Bridge", ""); + at.put("Method.Varargs", ""); + at.put("Class.Enum", ""); + at.put("*.Signature", "RSH"); + //at.put("*.Deprecated", ""); + //at.put("*.Synthetic", ""); + at.put("Field.ConstantValue", "KQH"); + at.put("Class.SourceFile", "RUH"); + at.put("Class.InnerClasses", "NH[RCHRCHRUHFH]"); + at.put("Code.LineNumberTable", "NH[PHH]"); + at.put("Code.LocalVariableTable", "NH[PHHRUHRSHH]"); + at.put("Code.LocalVariableTypeTable", "NH[PHHRUHRSHH]"); + at.put("Method.Exceptions", "NH[RCH]"); + at.put("Method.Code", "..."); + at.put("Code.StackMapTable", "..."); + //at.put("Code.StkMapX", "..."); + if (true) { + at.put("Code.StackMapTable", + "[NH[(1)]]" + + "[TB" + + "(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79" + + ",80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95" + + ",96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111" + + ",112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127" + + ")[(4)]" + + "(247)[H(4)]" + + "(248)[H]" + + "(249)[H]" + + "(250)[H]" + + "(251)[H]" + + "(252)[H(4)]" + + "(253)[H(4)(4)]" + + "(254)[H(4)(4)(4)]" + + "(255)[H(2)(3)]" + + "()[]]" + + "[NH[(4)]]" + + "[NH[(4)]]" + + "[TB" + + ("(0)[]" + + "(1)[](2)[](3)[](4)[]" + + "(5)[](6)[]" + + "(7)[RCH]" + + "(8)[PH]" + + "()[]]")); + } + + at.put("Class.EnclosingMethod", "RCHRDH");//RDNH + + // Layouts of metadata attrs: + String vpf = "["; + String ipf = "["; + String apf = "["; + String mdanno2 = "" + + "RSHNH[RUH(3)]]" + + ("[TB" + + "(\\B,\\C,\\I,\\S,\\Z)[KIH]" + + "(\\D)[KDH]" + + "(\\F)[KFH]" + + "(\\J)[KJH]" + + "(\\c)[RSH]" + + "(\\e)[RSHRUH]" + + "(\\s)[RUH]" + + "(\\@)[(2)]" + + "(\\[)[NH[(3)]]" + + "()[]" + + "]"); + String visanno = "[NH[(2)]][(1)]" + vpf + mdanno2; + String invanno = "[NH[(2)]][(1)]" + ipf + mdanno2; + String vparamanno = "" + + "[NB[(1)]][NH[(2)]]" + + apf + mdanno2; + String iparamanno = "" + + "[NB[(1)]][NH[(2)]]" + + apf + mdanno2; + String mdannodef = "[(3)][(1)]" + apf + mdanno2; + String[] mdplaces = {"Class", "Field", "Method"}; + for (String place : mdplaces) { + at.put(place + ".RuntimeVisibleAnnotations", visanno); + at.put(place + ".RuntimeInvisibleAnnotations", invanno); + } + at.put("Method.RuntimeVisibleParameterAnnotations", vparamanno); + at.put("Method.RuntimeInvisibleParameterAnnotations", iparamanno); + at.put("Method.AnnotationDefault", mdannodef); + + attrTypesBacking = at; + attrTypesInit = Collections.unmodifiableMap(at); + } + + ; + private static final String[] jcovAttrTypes = { + "Code.CoverageTable=NH[PHHII]", + "Code.CharacterRangeTable=NH[PHPOHIIH]", + "Class.SourceID=RUH", + "Class.CompilationID=RUH" + }; + protected static final String[][] modifierNames = { + {"public"}, + {"private"}, + {"protected"}, + {"static"}, + {"final"}, + {"synchronized"}, + {null, "volatile", "bridge"}, + {null, "transient", "varargs"}, + {null, null, "native"}, + {"interface"}, + {"abstract"}, + {"strictfp"}, + {"synthetic"}, + {"annotation"}, + {"enum"},}; + protected static final String EIGHT_BIT_CHAR_ENCODING = "ISO8859_1"; + protected static final String UTF8_ENCODING = "UTF8"; + // What XML tags are used by this syntax, apart from attributes? + protected static final Set nonAttrTags; + + static { + HashSet tagSet = new HashSet(); + Collections.addAll(tagSet, new String[]{ + "ConstantPool",// the CP + "Class", // the class + "Interface", // implemented interfaces + "Method", // methods + "Field", // fields + "Handler", // exception handler pseudo-attribute + "Attribute", // unparsed attribute + "Bytes", // bytecodes + "Instructions" // bytecodes, parsed + }); + nonAttrTags = Collections.unmodifiableSet(tagSet); + } + + // Accessors. + public static Set nonAttrTags() { + return nonAttrTags; + } + + public static String cpTagName(int t) { + t &= 0xFF; + String ts = null; + if (t < cpTagName.length) { + ts = cpTagName[t]; + } + if (ts != null) { + return ts; + } + return ("UnknownTag" + (int) t).intern(); + } + + public static int cpTagValue(String name) { + for (int t = 0; t < cpTagName.length; t++) { + if (name.equals(cpTagName[t])) { + return t; + } + } + return 0; + } + + public static String itemTagName(int t) { + t &= 0xFF; + String ts = null; + if (t < itemTagName.length) { + ts = itemTagName[t]; + } + if (ts != null) { + return ts; + } + return ("UnknownItem" + (int) t).intern(); + } + + public static int itemTagValue(String name) { + for (int t = 0; t < itemTagName.length; t++) { + if (name.equals(itemTagName[t])) { + return t; + } + } + return -1; + } + + public void addJcovAttrTypes() { + addAttrTypes(jcovAttrTypes); + } + // Public methods for declaring attribute types. + protected Map attrTypes = attrTypesInit; + + public void addAttrType(String opt) { + int eqpos = opt.indexOf('='); + addAttrType(opt.substring(0, eqpos), opt.substring(eqpos + 1)); + } + + public void addAttrTypes(String[] opts) { + for (String opt : opts) { + addAttrType(opt); + } + } + + private void checkAttr(String attr) { + if (!attr.startsWith("Class.") + && !attr.startsWith("Field.") + && !attr.startsWith("Method.") + && !attr.startsWith("Code.") + && !attr.startsWith("*.")) { + throw new IllegalArgumentException("attr name must start with 'Class.', etc."); + } + String uattr = attr.substring(attr.indexOf('.') + 1); + if (nonAttrTags.contains(uattr)) { + throw new IllegalArgumentException("attr name must not be one of " + nonAttrTags); + } + } + + private void checkAttrs(Map at) { + for (String attr : at.keySet()) { + checkAttr(attr); + } + } + + private void modAttrs() { + if (attrTypes == attrTypesInit) { + // Make modifiable. + attrTypes = new HashMap(attrTypesBacking); + } + } + + public void addAttrType(String attr, String fmt) { + checkAttr(attr); + modAttrs(); + attrTypes.put(attr, fmt); + } + + public void addAttrTypes(Map at) { + checkAttrs(at); + modAttrs(); + attrTypes.putAll(at); + } + + public Map getAttrTypes() { + if (attrTypes == attrTypesInit) { + return attrTypes; + } + return Collections.unmodifiableMap(attrTypes); + } + + public void setAttrTypes(Map at) { + checkAttrs(at); + modAttrs(); + attrTypes.keySet().retainAll(at.keySet()); + attrTypes.putAll(at); + } + + // attr format helpers + protected static boolean matchTag(int tagValue, String caseStr) { + //System.out.println("matchTag "+tagValue+" in "+caseStr); + for (int pos = 0, max = caseStr.length(), comma; + pos < max; + pos = comma + 1) { + int caseValue; + if (caseStr.charAt(pos) == '\\') { + caseValue = caseStr.charAt(pos + 1); + comma = pos + 2; + assert (comma == max || caseStr.charAt(comma) == ','); + } else { + comma = caseStr.indexOf(',', pos); + if (comma < 0) { + comma = max; + } + caseValue = Integer.parseInt(caseStr.substring(pos, comma)); + } + if (tagValue == caseValue) { + return true; + } + } + return false; + } + + protected static String[] getBodies(String type) { + ArrayList bodies = new ArrayList(); + for (int i = 0; i < type.length();) { + String body = getBody(type, i); + bodies.add(body); + i += body.length() + 2; // skip body and brackets + } + return bodies.toArray(new String[bodies.size()]); + } + + protected static String getBody(String type, int i) { + assert (type.charAt(i) == '['); + int next = ++i; // skip bracket + for (int depth = 1; depth > 0; next++) { + switch (type.charAt(next)) { + case '[': + depth++; + break; + case ']': + depth--; + break; + case '(': + next = type.indexOf(')', next); + break; + case '<': + next = type.indexOf('>', next); + break; + } + assert (next > 0); + } + --next; // get before bracket + assert (type.charAt(next) == ']'); + return type.substring(i, next); + } + + public Element makeCPDigest(int length) { + MessageDigest md; + try { + md = MessageDigest.getInstance("MD5"); + } catch (java.security.NoSuchAlgorithmException ee) { + throw new Error(ee); + } + int items = 0; + for (Element e : cpool.elements()) { + if (items == length) { + break; + } + if (cpTagNames.contains(e.getName())) { + items += 1; + md.update((byte) cpTagValue(e.getName())); + try { + md.update(e.getText().toString().getBytes(UTF8_ENCODING)); + } catch (java.io.UnsupportedEncodingException ee) { + throw new Error(ee); + } + } + } + ByteBuffer bb = ByteBuffer.wrap(md.digest()); + String l0 = Long.toHexString(bb.getLong(0)); + String l1 = Long.toHexString(bb.getLong(8)); + while (l0.length() < 16) { + l0 = "0" + l0; + } + while (l1.length() < 16) { + l1 = "0" + l1; + } + return new Element("Digest", + "length", "" + items, + "bytes", l0 + l1); + } + + public Element getCPDigest(int length) { + if (length == -1) { + length = cpool.countAll(XMLKit.elementFilter(cpTagNames)); + } + for (Element md : cpool.findAllElements("Digest").elements()) { + if (md.getAttrLong("length") == length) { + return md; + } + } + Element md = makeCPDigest(length); + cpool.add(md); + return md; + } + + public Element getCPDigest() { + return getCPDigest(-1); + } + + public boolean checkCPDigest(Element md) { + return md.equals(getCPDigest((int) md.getAttrLong("length"))); + } + + public static int computeInterfaceNum(String intMethRef) { + intMethRef = intMethRef.substring(1 + intMethRef.lastIndexOf(' ')); + if (!intMethRef.startsWith("(")) { + return -1; + } + int signum = 1; // start with one for "this" + scanSig: + for (int i = 1; i < intMethRef.length(); i++) { + char ch = intMethRef.charAt(i); + signum++; + switch (ch) { + case ')': + --signum; + break scanSig; + case 'L': + i = intMethRef.indexOf(';', i); + break; + case '[': + while (ch == '[') { + ch = intMethRef.charAt(++i); + } + if (ch == 'L') { + i = intMethRef.indexOf(';', i); + } + break; + } + } + int num = (signum << 8) | 0; + //System.out.println("computeInterfaceNum "+intMethRef+" => "+num); + return num; + } + // Protected state for representing the class file. + protected Element cfile; // + protected Element cpool; // + protected Element klass; // + protected Element currentMember; // varies during scans + protected Element currentCode; // varies during scans +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java new file mode 100644 index 00000000000..037de37e540 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java @@ -0,0 +1,818 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- + +import java.util.*; +import java.lang.reflect.*; +import java.io.*; +import xmlkit.XMLKit.Element; +/* + * @author jrose + */ +public class ClassWriter extends ClassSyntax implements ClassSyntax.GetCPIndex { + + private static final CommandLineParser CLP = new CommandLineParser("" + + "-source: +> = \n" + + "-dest: +> = \n" + + "-encoding: +> = \n" + + "-parseBytes $ \n" + + "- *? \n" + + "\n"); + + public static void main(String[] ava) throws IOException { + ArrayList av = new ArrayList(Arrays.asList(ava)); + HashMap props = new HashMap(); + props.put("-encoding:", "UTF8"); // default + CLP.parse(av, props); + File source = asFile(props.get("-source:")); + File dest = asFile(props.get("-dest:")); + String encoding = props.get("-encoding:"); + boolean parseBytes = props.containsKey("-parseBytes"); + boolean destMade = false; + + for (String a : av) { + File f; + File inf = new File(source, a); + System.out.println("Reading " + inf); + Element e; + if (inf.getName().endsWith(".class")) { + ClassReader cr = new ClassReader(); + cr.parseBytes = parseBytes; + e = cr.readFrom(inf); + f = new File(a); + } else if (inf.getName().endsWith(".xml")) { + InputStream in = new FileInputStream(inf); + Reader inw = ClassReader.makeReader(in, encoding); + e = XMLKit.readFrom(inw); + e.findAllInTree(XMLKit.and(XMLKit.elementFilter(nonAttrTags()), + XMLKit.methodFilter(Element.method("trimText")))); + //System.out.println(e); + inw.close(); + f = new File(a.substring(0, a.length() - ".xml".length()) + ".class"); + } else { + System.out.println("Warning: unknown input " + a); + continue; + } + // Now write it: + if (!destMade) { + destMade = true; + if (dest == null) { + dest = File.createTempFile("TestOut", ".dir", new File(".")); + dest.delete(); + System.out.println("Writing results to " + dest); + } + if (!(dest.isDirectory() || dest.mkdir())) { + throw new RuntimeException("Cannot create " + dest); + } + } + File outf = new File(dest, f.isAbsolute() ? f.getName() : f.getPath()); + outf.getParentFile().mkdirs(); + new ClassWriter(e).writeTo(outf); + } + } + + private static File asFile(String str) { + return (str == null) ? null : new File(str); + } + + public void writeTo(File file) throws IOException { + OutputStream out = null; + try { + out = new BufferedOutputStream(new FileOutputStream(file)); + writeTo(out); + } finally { + if (out != null) { + out.close(); + } + } + } + protected String[] callables; // varies + protected int cpoolSize = 0; + protected HashMap attrTypesByTag; + protected OutputStream out; + protected HashMap cpMap = new HashMap(); + protected ArrayList attrBufs = new ArrayList(); + + private void setupAttrTypes() { + attrTypesByTag = new HashMap(); + for (String key : attrTypes.keySet()) { + String pfx = key.substring(0, key.indexOf('.') + 1); + String val = attrTypes.get(key); + int pos = val.indexOf('<'); + if (pos >= 0) { + String tag = val.substring(pos + 1, val.indexOf('>', pos)); + attrTypesByTag.put(pfx + tag, key); + } + } + //System.out.println("attrTypesByTag: "+attrTypesByTag); + } + + protected ByteArrayOutputStream getAttrBuf() { + int nab = attrBufs.size(); + if (nab == 0) { + return new ByteArrayOutputStream(1024); + } + ByteArrayOutputStream ab = attrBufs.get(nab - 1); + attrBufs.remove(nab - 1); + return ab; + } + + protected void putAttrBuf(ByteArrayOutputStream ab) { + ab.reset(); + attrBufs.add(ab); + } + + public ClassWriter(Element root) { + this(root, null); + } + + public ClassWriter(Element root, ClassSyntax cr) { + if (cr != null) { + attrTypes = cr.attrTypes; + } + setupAttrTypes(); + if (root.getName() == "ClassFile") { + cfile = root; + cpool = root.findElement("ConstantPool"); + klass = root.findElement("Class"); + } else if (root.getName() == "Class") { + cfile = new Element("ClassFile", + new String[]{ + "magic", String.valueOf(0xCAFEBABE), + "minver", "0", "majver", "46",}); + cpool = new Element("ConstantPool"); + klass = root; + } else { + throw new IllegalArgumentException("bad element type " + root.getName()); + } + if (cpool == null) { + cpool = new Element("ConstantPool"); + } + + int cpLen = 1 + cpool.size(); + for (Element c : cpool.elements()) { + int id = (int) c.getAttrLong("id"); + int tag = cpTagValue(c.getName()); + setCPIndex(tag, c.getText().toString(), id); + switch (tag) { + case CONSTANT_Long: + case CONSTANT_Double: + cpLen += 1; + } + } + cpoolSize = cpLen; + } + + public int findCPIndex(int tag, String name) { + if (name == null) { + return 0; + } + int[] ids = cpMap.get(name.toString()); + return (ids == null) ? 0 : ids[tag]; + } + + public int getCPIndex(int tag, String name) { + //System.out.println("getCPIndex "+cpTagName(tag)+" "+name); + if (name == null) { + return 0; + } + int id = findCPIndex(tag, name); + if (id == 0) { + id = cpoolSize; + cpoolSize += 1; + setCPIndex(tag, name, id); + cpool.add(new Element(cpTagName(tag), + new String[]{"id", "" + id}, + new Object[]{name})); + int pos; + switch (tag) { + case CONSTANT_Long: + case CONSTANT_Double: + cpoolSize += 1; + break; + case CONSTANT_Class: + case CONSTANT_String: + getCPIndex(CONSTANT_Utf8, name); + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + pos = name.indexOf(' '); + getCPIndex(CONSTANT_Class, name.substring(0, pos)); + getCPIndex(CONSTANT_NameAndType, name.substring(pos + 1)); + break; + case CONSTANT_NameAndType: + pos = name.indexOf(' '); + getCPIndex(CONSTANT_Utf8, name.substring(0, pos)); + getCPIndex(CONSTANT_Utf8, name.substring(pos + 1)); + break; + } + } + return id; + } + + public void setCPIndex(int tag, String name, int id) { + //System.out.println("setCPIndex id="+id+" tag="+tag+" name="+name); + int[] ids = cpMap.get(name); + if (ids == null) { + cpMap.put(name, ids = new int[13]); + } + if (ids[tag] != 0 && ids[tag] != id) { + System.out.println("Warning: Duplicate CP entries for " + ids[tag] + " and " + id); + } + //assert(ids[tag] == 0 || ids[tag] == id); + ids[tag] = id; + } + + public int parseFlags(String flagString) { + int flags = 0; + int i = -1; + for (String[] names : modifierNames) { + ++i; + for (String name : names) { + if (name == null) { + continue; + } + int pos = flagString.indexOf(name); + if (pos >= 0) { + flags |= (1 << i); + } + } + } + return flags; + } + + public void writeTo(OutputStream realOut) throws IOException { + OutputStream headOut = realOut; + ByteArrayOutputStream tailOut = new ByteArrayOutputStream(); + + // write the body of the class file first + this.out = tailOut; + writeClass(); + + // write the file header last + this.out = headOut; + u4((int) cfile.getAttrLong("magic")); + u2((int) cfile.getAttrLong("minver")); + u2((int) cfile.getAttrLong("majver")); + writeCP(); + + // recopy the file tail + this.out = null; + tailOut.writeTo(realOut); + } + + void writeClass() throws IOException { + int flags = parseFlags(klass.getAttr("flags")); + flags ^= Modifier.SYNCHRONIZED; + u2(flags); + cpRef(CONSTANT_Class, klass.getAttr("name")); + cpRef(CONSTANT_Class, klass.getAttr("super")); + Element interfaces = klass.findAllElements("Interface"); + u2(interfaces.size()); + for (Element e : interfaces.elements()) { + cpRef(CONSTANT_Class, e.getAttr("name")); + } + for (int isMethod = 0; isMethod <= 1; isMethod++) { + Element members = klass.findAllElements(isMethod != 0 ? "Method" : "Field"); + u2(members.size()); + for (Element m : members.elements()) { + writeMember(m, isMethod != 0); + } + } + writeAttributesFor(klass); + } + + private void writeMember(Element member, boolean isMethod) throws IOException { + //System.out.println("writeMember "+member); + u2(parseFlags(member.getAttr("flags"))); + cpRef(CONSTANT_Utf8, member.getAttr("name")); + cpRef(CONSTANT_Utf8, member.getAttr("type")); + writeAttributesFor(member); + } + + protected void writeAttributesFor(Element x) throws IOException { + LinkedHashSet attrNames = new LinkedHashSet(); + for (Element e : x.elements()) { + attrNames.add(e.getName()); // uniquifying + } + attrNames.removeAll(nonAttrTags()); + u2(attrNames.size()); + if (attrNames.isEmpty()) { + return; + } + Element prevCurrent; + if (x.getName() == "Code") { + prevCurrent = currentCode; + currentCode = x; + } else { + prevCurrent = currentMember; + currentMember = x; + } + OutputStream realOut = this.out; + for (String utag : attrNames) { + String qtag = x.getName() + "." + utag; + String wtag = "*." + utag; + String key = attrTypesByTag.get(qtag); + if (key == null) { + key = attrTypesByTag.get(wtag); + } + String type = attrTypes.get(key); + //System.out.println("tag "+qtag+" => key "+key+"; type "+type); + Element attrs = x.findAllElements(utag); + ByteArrayOutputStream attrBuf = getAttrBuf(); + if (type == null) { + if (attrs.size() != 1 || !attrs.get(0).equals(new Element(utag))) { + System.out.println("Warning: No attribute type description: " + qtag); + } + key = wtag; + } else { + try { + this.out = attrBuf; + // unparse according to type desc. + if (type.equals("...")) { + writeCode((Element) attrs.get(0)); // assume only 1 + } else if (type.equals("...")) { + writeStackMap(attrs, false); + } else if (type.equals("...")) { + writeStackMap(attrs, true); + } else if (type.startsWith("[")) { + writeAttributeRecursive(attrs, type); + } else { + writeAttribute(attrs, type); + } + } finally { + //System.out.println("Attr Bytes = \""+attrBuf.toString(EIGHT_BIT_CHAR_ENCODING).replace('"', (char)('"'|0x80))+"\""); + this.out = realOut; + } + } + cpRef(CONSTANT_Utf8, key.substring(key.indexOf('.') + 1)); + u4(attrBuf.size()); + attrBuf.writeTo(out); + putAttrBuf(attrBuf); + } + if (x.getName() == "Code") { + currentCode = prevCurrent; + } else { + currentMember = prevCurrent; + } + } + + private void writeAttributeRecursive(Element aval, String type) throws IOException { + assert (callables == null); + callables = getBodies(type); + writeAttribute(aval, callables[0]); + callables = null; + } + + private void writeAttribute(Element aval, String type) throws IOException { + //System.out.println("writeAttribute "+aval+" using "+type); + String nextAttrName = null; + boolean afterElemHead = false; + for (int len = type.length(), next, i = 0; i < len; i = next) { + int value; + char intKind; + int tag; + int sigChar; + String attrValue; + switch (type.charAt(i)) { + case '<': + assert (nextAttrName == null); + next = type.indexOf('>', i); + String form = type.substring(i + 1, next++); + if (form.indexOf('=') < 0) { + // elem_placement = '<' elemname '>' + if (aval.isAnonymous()) { + assert (aval.size() == 1); + aval = (Element) aval.get(0); + } + assert (aval.getName().equals(form)) : aval + " // " + form; + afterElemHead = true; + } else { + // attr_placement = '(' attrname '=' (value)? ')' + int eqPos = form.indexOf('='); + assert (eqPos >= 0); + nextAttrName = form.substring(0, eqPos).intern(); + if (eqPos != form.length() - 1) { + // value is implicit, not placed in file + nextAttrName = null; + } + afterElemHead = false; + } + continue; + case '(': + next = type.indexOf(')', ++i); + int callee = Integer.parseInt(type.substring(i, next++)); + writeAttribute(aval, callables[callee]); + continue; + case 'N': // replication = 'N' int '[' type ... ']' + { + assert (nextAttrName == null); + afterElemHead = false; + char countType = type.charAt(i + 1); + next = i + 2; + String type1 = getBody(type, next); + Element elems = aval; + if (type1.startsWith("<")) { + // Select only matching members of aval. + String elemName = type1.substring(1, type1.indexOf('>')); + elems = aval.findAllElements(elemName); + } + putInt(elems.size(), countType); + next += type1.length() + 2; // skip body and brackets + for (Element elem : elems.elements()) { + writeAttribute(elem, type1); + } + } + continue; + case 'T': // union = 'T' any_int union_case* '(' ')' '[' body ']' + // write the value + value = (int) aval.getAttrLong("tag"); + assert (aval.getAttr("tag") != null) : aval; + intKind = type.charAt(++i); + if (intKind == 'S') { + intKind = type.charAt(++i); + } + putInt(value, intKind); + nextAttrName = null; + afterElemHead = false; + ++i; // skip the int type char + // union_case = '(' ('-')? digit+ ')' '[' body ']' + for (boolean foundCase = false;;) { + assert (type.charAt(i) == '('); + next = type.indexOf(')', ++i); + assert (next >= i); + String caseStr = type.substring(i, next++); + String type1 = getBody(type, next); + next += type1.length() + 2; // skip body and brackets + boolean lastCase = (caseStr.length() == 0); + if (!foundCase + && (lastCase || matchTag(value, caseStr))) { + foundCase = true; + // Execute this body. + writeAttribute(aval, type1); + } + if (lastCase) { + break; + } + } + continue; + case 'B': + case 'H': + case 'I': // int = oneof "BHI" + value = (int) aval.getAttrLong(nextAttrName); + intKind = type.charAt(i); + next = i + 1; + break; + case 'K': + sigChar = type.charAt(i + 1); + if (sigChar == 'Q') { + assert (currentMember.getName() == "Field"); + assert (aval.getName() == "ConstantValue"); + String sig = currentMember.getAttr("type"); + sigChar = sig.charAt(0); + switch (sigChar) { + case 'Z': + case 'B': + case 'C': + case 'S': + sigChar = 'I'; + break; + } + } + switch (sigChar) { + case 'I': + tag = CONSTANT_Integer; + break; + case 'J': + tag = CONSTANT_Long; + break; + case 'F': + tag = CONSTANT_Float; + break; + case 'D': + tag = CONSTANT_Double; + break; + case 'L': + tag = CONSTANT_String; + break; + default: + assert (false); + tag = 0; + } + assert (type.charAt(i + 2) == 'H'); // only H works for now + next = i + 3; + assert (afterElemHead || nextAttrName != null); + //System.out.println("get attr "+nextAttrName+" in "+aval); + if (nextAttrName != null) { + attrValue = aval.getAttr(nextAttrName); + assert (attrValue != null); + } else { + assert (aval.isText()) : aval; + attrValue = aval.getText().toString(); + } + value = getCPIndex(tag, attrValue); + intKind = 'H'; //type.charAt(i+2); + break; + case 'R': + sigChar = type.charAt(i + 1); + switch (sigChar) { + case 'C': + tag = CONSTANT_Class; + break; + case 'S': + tag = CONSTANT_Utf8; + break; + case 'D': + tag = CONSTANT_Class; + break; + case 'F': + tag = CONSTANT_Fieldref; + break; + case 'M': + tag = CONSTANT_Methodref; + break; + case 'I': + tag = CONSTANT_InterfaceMethodref; + break; + case 'U': + tag = CONSTANT_Utf8; + break; + //case 'Q': tag = CONSTANT_Class; break; + default: + assert (false); + tag = 0; + } + assert (type.charAt(i + 2) == 'H'); // only H works for now + next = i + 3; + assert (afterElemHead || nextAttrName != null); + //System.out.println("get attr "+nextAttrName+" in "+aval); + if (nextAttrName != null) { + attrValue = aval.getAttr(nextAttrName); + } else if (aval.hasText()) { + attrValue = aval.getText().toString(); + } else { + attrValue = null; + } + value = getCPIndex(tag, attrValue); + intKind = 'H'; //type.charAt(i+2); + break; + case 'P': // bci = 'P' int + case 'S': // signed_int = 'S' int + next = i + 2; + value = (int) aval.getAttrLong(nextAttrName); + intKind = type.charAt(i + 1); + break; + case 'F': + next = i + 2; + value = parseFlags(aval.getAttr(nextAttrName)); + intKind = type.charAt(i + 1); + break; + default: + throw new RuntimeException("bad attr format '" + type.charAt(i) + "': " + type); + } + // write the value + putInt(value, intKind); + nextAttrName = null; + afterElemHead = false; + } + assert (nextAttrName == null); + } + + private void putInt(int x, char ch) throws IOException { + switch (ch) { + case 'B': + u1(x); + break; + case 'H': + u2(x); + break; + case 'I': + u4(x); + break; + } + assert ("BHI".indexOf(ch) >= 0); + } + + private void writeCode(Element code) throws IOException { + //System.out.println("writeCode "+code); + //Element m = new Element(currentMember); m.remove(code); + //System.out.println(" in "+m); + int stack = (int) code.getAttrLong("stack"); + int local = (int) code.getAttrLong("local"); + Element bytes = code.findElement("Bytes"); + Element insns = code.findElement("Instructions"); + String bytecodes; + if (insns == null) { + bytecodes = bytes.getText().toString(); + } else { + bytecodes = InstructionSyntax.assemble(insns, this); + // Cache the assembled bytecodes: + bytes = new Element("Bytes", (String[]) null, bytecodes); + code.add(0, bytes); + } + u2(stack); + u2(local); + int length = bytecodes.length(); + u4(length); + for (int i = 0; i < length; i++) { + u1((byte) bytecodes.charAt(i)); + } + Element handlers = code.findAllElements("Handler"); + u2(handlers.size()); + for (Element handler : handlers.elements()) { + int start = (int) handler.getAttrLong("start"); + int end = (int) handler.getAttrLong("end"); + int catsh = (int) handler.getAttrLong("catch"); + u2(start); + u2(end); + u2(catsh); + cpRef(CONSTANT_Class, handler.getAttr("class")); + } + writeAttributesFor(code); + } + + protected void writeStackMap(Element attrs, boolean hasXOption) throws IOException { + Element bytes = currentCode.findElement("Bytes"); + assert (bytes != null && bytes.size() == 1); + int byteLength = ((String) bytes.get(0)).length(); + boolean uoffsetIsU4 = (byteLength >= (1 << 16)); + boolean ulocalvarIsU4 = currentCode.getAttrLong("local") >= (1 << 16); + boolean ustackIsU4 = currentCode.getAttrLong("stack") >= (1 << 16); + if (uoffsetIsU4) { + u4(attrs.size()); + } else { + u2(attrs.size()); + } + for (Element frame : attrs.elements()) { + int bci = (int) frame.getAttrLong("bci"); + if (uoffsetIsU4) { + u4(bci); + } else { + u2(bci); + } + if (hasXOption) { + u1((int) frame.getAttrLong("flags")); + } + // Scan local and stack types in this frame: + final int LOCALS = 0, STACK = 1; + for (int j = LOCALS; j <= STACK; j++) { + Element types = frame.findElement(j == LOCALS ? "Local" : "Stack"); + int typeSize = (types == null) ? 0 : types.size(); + if (j == LOCALS) { + if (ulocalvarIsU4) { + u4(typeSize); + } else { + u2(typeSize); + } + } else { // STACK + if (ustackIsU4) { + u4(typeSize); + } else { + u2(typeSize); + } + } + if (types == null) { + continue; + } + for (Element type : types.elements()) { + int tag = itemTagValue(type.getName()); + u1(tag); + switch (tag) { + case ITEM_Object: + cpRef(CONSTANT_Class, type.getAttr("class")); + break; + case ITEM_Uninitialized: + case ITEM_ReturnAddress: { + int offset = (int) type.getAttrLong("bci"); + if (uoffsetIsU4) { + u4(offset); + } else { + u2(offset); + } + } + break; + } + } + } + } + } + + public void writeCP() throws IOException { + int cpLen = cpoolSize; + u2(cpLen); + ByteArrayOutputStream buf = getAttrBuf(); + for (Element c : cpool.elements()) { + if (!c.isText()) { + System.out.println("## !isText " + c); + } + int id = (int) c.getAttrLong("id"); + int tag = cpTagValue(c.getName()); + String name = c.getText().toString(); + int pos; + u1(tag); + switch (tag) { + case CONSTANT_Utf8: { + int done = 0; + buf.reset(); + int nameLen = name.length(); + while (done < nameLen) { + int next = name.indexOf((char) 0, done); + if (next < 0) { + next = nameLen; + } + if (done < next) { + buf.write(name.substring(done, next).getBytes(UTF8_ENCODING)); + } + if (next < nameLen) { + buf.write(0300); + buf.write(0200); + next++; + } + done = next; + } + u2(buf.size()); + buf.writeTo(out); + } + break; + case CONSTANT_Integer: + u4(Integer.parseInt(name)); + break; + case CONSTANT_Float: + u4(Float.floatToIntBits(Float.parseFloat(name))); + break; + case CONSTANT_Long: + u8(Long.parseLong(name)); + //i += 1; // no need: extra cp slot is implicit + break; + case CONSTANT_Double: + u8(Double.doubleToLongBits(Double.parseDouble(name))); + //i += 1; // no need: extra cp slot is implicit + break; + case CONSTANT_Class: + case CONSTANT_String: + u2(getCPIndex(CONSTANT_Utf8, name)); + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + pos = name.indexOf(' '); + u2(getCPIndex(CONSTANT_Class, name.substring(0, pos))); + u2(getCPIndex(CONSTANT_NameAndType, name.substring(pos + 1))); + break; + case CONSTANT_NameAndType: + pos = name.indexOf(' '); + u2(getCPIndex(CONSTANT_Utf8, name.substring(0, pos))); + u2(getCPIndex(CONSTANT_Utf8, name.substring(pos + 1))); + break; + } + } + putAttrBuf(buf); + } + + public void cpRef(int tag, String name) throws IOException { + u2(getCPIndex(tag, name)); + } + + public void u8(long x) throws IOException { + u4((int) (x >>> 32)); + u4((int) (x >>> 0)); + } + + public void u4(int x) throws IOException { + u2(x >>> 16); + u2(x >>> 0); + } + + public void u2(int x) throws IOException { + u1(x >>> 8); + u1(x >>> 0); + } + + public void u1(int x) throws IOException { + out.write(x & 0xFF); + } +} + diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/CommandLineParser.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/CommandLineParser.java new file mode 100644 index 00000000000..852b4b3f4a3 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/CommandLineParser.java @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- + +import java.util.*; +/* + * @author jrose + */ +public class CommandLineParser { + + public CommandLineParser(String optionString) { + setOptionMap(optionString); + } + TreeMap optionMap; + + public void setOptionMap(String options) { + // Convert options string into optLines dictionary. + TreeMap optmap = new TreeMap(); + loadOptmap: + for (String optline : options.split("\n")) { + String[] words = optline.split("\\p{Space}+"); + if (words.length == 0) { + continue loadOptmap; + } + String opt = words[0]; + words[0] = ""; // initial word is not a spec + if (opt.length() == 0 && words.length >= 1) { + opt = words[1]; // initial "word" is empty due to leading ' ' + words[1] = ""; + } + if (opt.length() == 0) { + continue loadOptmap; + } + String[] prevWords = optmap.put(opt, words); + if (prevWords != null) { + throw new RuntimeException("duplicate option: " + + optline.trim()); + } + } + optionMap = optmap; + } + + public String getOptionMap() { + TreeMap optmap = optionMap; + StringBuffer sb = new StringBuffer(); + for (String opt : optmap.keySet()) { + sb.append(opt); + for (String spec : optmap.get(opt)) { + sb.append(' ').append(spec); + } + sb.append('\n'); + } + return sb.toString(); + } + + /** + * Remove a set of command-line options from args, + * storing them in the properties map in a canonicalized form. + */ + public String parse(List args, Map properties) { + //System.out.println(args+" // "+properties); + + String resultString = null; + TreeMap optmap = optionMap; + + // State machine for parsing a command line. + ListIterator argp = args.listIterator(); + ListIterator pbp = new ArrayList().listIterator(); + doArgs: + for (;;) { + // One trip through this loop per argument. + // Multiple trips per option only if several options per argument. + String arg; + if (pbp.hasPrevious()) { + arg = pbp.previous(); + pbp.remove(); + } else if (argp.hasNext()) { + arg = argp.next(); + } else { + // No more arguments at all. + break doArgs; + } + tryOpt: + for (int optlen = arg.length();; optlen--) { + // One time through this loop for each matching arg prefix. + String opt; + // Match some prefix of the argument to a key in optmap. + findOpt: + for (;;) { + opt = arg.substring(0, optlen); + if (optmap.containsKey(opt)) { + break findOpt; + } + if (optlen == 0) { + break tryOpt; + } + // Decide on a smaller prefix to search for. + SortedMap pfxmap = optmap.headMap(opt); + // pfxmap.lastKey is no shorter than any prefix in optmap. + int len = pfxmap.isEmpty() ? 0 : pfxmap.lastKey().length(); + optlen = Math.min(len, optlen - 1); + opt = arg.substring(0, optlen); + // (Note: We could cut opt down to its common prefix with + // pfxmap.lastKey, but that wouldn't save many cycles.) + } + opt = opt.intern(); + assert (arg.startsWith(opt)); + assert (opt.length() == optlen); + String val = arg.substring(optlen); // arg == opt+val + + // Execute the option processing specs for this opt. + // If no actions are taken, then look for a shorter prefix. + boolean didAction = false; + boolean isError = false; + + int pbpMark = pbp.nextIndex(); // in case of backtracking + String[] specs = optmap.get(opt); + eachSpec: + for (String spec : specs) { + if (spec.length() == 0) { + continue eachSpec; + } + if (spec.startsWith("#")) { + break eachSpec; + } + int sidx = 0; + char specop = spec.charAt(sidx++); + + // Deal with '+'/'*' prefixes (spec conditions). + boolean ok; + switch (specop) { + case '+': + // + means we want an non-empty val suffix. + ok = (val.length() != 0); + specop = spec.charAt(sidx++); + break; + case '*': + // * means we accept empty or non-empty + ok = true; + specop = spec.charAt(sidx++); + break; + default: + // No condition prefix means we require an exact + // match, as indicated by an empty val suffix. + ok = (val.length() == 0); + break; + } + if (!ok) { + continue eachSpec; + } + + String specarg = spec.substring(sidx); + switch (specop) { + case '.': // terminate the option sequence + resultString = (specarg.length() != 0) ? specarg.intern() : opt; + break doArgs; + case '?': // abort the option sequence + resultString = (specarg.length() != 0) ? specarg.intern() : arg; + isError = true; + break eachSpec; + case '@': // change the effective opt name + opt = specarg.intern(); + break; + case '>': // shift remaining arg val to next arg + pbp.add(specarg + val); // push a new argument + val = ""; + break; + case '!': // negation option + String negopt = (specarg.length() != 0) ? specarg.intern() : opt; + properties.remove(negopt); + properties.put(negopt, null); // leave placeholder + didAction = true; + break; + case '$': // normal "boolean" option + String boolval; + if (specarg.length() != 0) { + // If there is a given spec token, store it. + boolval = specarg; + } else { + String old = properties.get(opt); + if (old == null || old.length() == 0) { + boolval = "1"; + } else { + // Increment any previous value as a numeral. + boolval = "" + (1 + Integer.parseInt(old)); + } + } + properties.put(opt, boolval); + didAction = true; + break; + case '=': // "string" option + case '&': // "collection" option + // Read an option. + boolean append = (specop == '&'); + String strval; + if (pbp.hasPrevious()) { + strval = pbp.previous(); + pbp.remove(); + } else if (argp.hasNext()) { + strval = argp.next(); + } else { + resultString = arg + " ?"; + isError = true; + break eachSpec; + } + if (append) { + String old = properties.get(opt); + if (old != null) { + // Append new val to old with embedded delim. + String delim = specarg; + if (delim.length() == 0) { + delim = " "; + } + strval = old + specarg + strval; + } + } + properties.put(opt, strval); + didAction = true; + break; + default: + throw new RuntimeException("bad spec for " + + opt + ": " + spec); + } + } + + // Done processing specs. + if (didAction && !isError) { + continue doArgs; + } + + // The specs should have done something, but did not. + while (pbp.nextIndex() > pbpMark) { + // Remove anything pushed during these specs. + pbp.previous(); + pbp.remove(); + } + + if (isError) { + throw new IllegalArgumentException(resultString); + } + + if (optlen == 0) { + // We cannot try a shorter matching option. + break tryOpt; + } + } + + // If we come here, there was no matching option. + // So, push back the argument, and return to caller. + pbp.add(arg); + break doArgs; + } + // Report number of arguments consumed. + args.subList(0, argp.nextIndex()).clear(); + // Report any unconsumed partial argument. + while (pbp.hasPrevious()) { + args.add(0, pbp.previous()); + } + //System.out.println(args+" // "+properties+" -> "+resultString); + return resultString; + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java new file mode 100644 index 00000000000..cbe34e6b960 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- + +import xmlkit.XMLKit.Element; +import java.util.HashMap; +/* + * @author jrose + */ +abstract class InstructionAssembler extends InstructionSyntax { + + InstructionAssembler() { + } + + public static String assemble(Element instructions, String pcAttrName, + ClassSyntax.GetCPIndex getCPI) { + int insCount = instructions.size(); + Element[] insElems = new Element[insCount]; + int[] elemToIndexMap; + int[] insLocs; + byte[] ops = new byte[insCount]; + int[] operands = new int[insCount]; + boolean[] isWide = new boolean[insCount]; + int[] branches; + int[] branchInsLocs; + HashMap labels = new HashMap(); + + final int WIDE = 0xc4; + final int GOTO = 0xa7; + final int GOTO_W = 0xc8; + final int GOTO_LEN = 3; + final int GOTO_W_LEN = 5; + assert ("wide".equals(bcNames[WIDE])); + assert ("goto".equals(bcNames[GOTO])); + assert ("goto_w".equals(bcNames[GOTO_W])); + assert (bcFormats[GOTO].length() == GOTO_LEN); + assert (bcFormats[GOTO_W].length() == GOTO_W_LEN); + + // Unpack instructions into temp. arrays, and find branches and labels. + { + elemToIndexMap = (pcAttrName != null) ? new int[insCount] : null; + int[] buffer = operands; + int id = 0; + int branchCount = 0; + for (int i = 0; i < insCount; i++) { + Element ins = (Element) instructions.get(i); + if (elemToIndexMap != null) { + elemToIndexMap[i] = (ins.getAttr(pcAttrName) != null ? id : -1); + } + String lab = ins.getAttr("pc"); + if (lab != null) { + labels.put(lab, String.valueOf(id)); + } + int op = opCode(ins.getName()); + if (op < 0) { + assert (ins.getAttr(pcAttrName) != null + || ins.getName().equals("label")); + continue; // delete PC holder element + } + if (op == WIDE) { //0xc4 + isWide[id] = true; // force wide format + continue; + } + if (bcFormats[op].indexOf('o') >= 0) { + buffer[branchCount++] = id; + } + if (bcFormats[op] == bcWideFormats[op]) { + isWide[id] = false; + } + insElems[id] = ins; + ops[id] = (byte) op; + id++; + } + insCount = id; // maybe we deleted some wide prefixes, etc. + branches = new int[branchCount + 1]; + System.arraycopy(buffer, 0, branches, 0, branchCount); + branches[branchCount] = -1; // sentinel + } + + // Compute instruction sizes. These sizes are final, + // except for branch instructions, which may need lengthening. + // Some instructions (ldc, bipush, iload, iinc) are automagically widened. + insLocs = new int[insCount + 1]; + int loc = 0; + for (int bn = 0, id = 0; id < insCount; id++) { + insLocs[id] = loc; + Element ins = insElems[id]; + int op = ops[id] & 0xFF; + String format = opFormat(op, isWide[id]); + // Make sure operands fit within the given format. + for (int j = 1, jlimit = format.length(); j < jlimit; j++) { + char fc = format.charAt(j); + int x = 0; + switch (fc) { + case 'l': + x = (int) ins.getAttrLong("loc"); + assert (x >= 0); + if (x > 0xFF && !isWide[id]) { + isWide[id] = true; + format = opFormat(op, isWide[id]); + } + assert (x <= 0xFFFF); + break; + case 'k': + char fc2 = format.charAt(Math.min(j + 1, format.length() - 1)); + x = getCPIndex(ins, fc2, getCPI); + if (x > 0xFF && j == jlimit - 1) { + assert (op == 0x12); //ldc + ops[id] = (byte) (op = 0x13); //ldc_w + format = opFormat(op); + } + assert (x <= 0xFFFF); + j++; // skip type-of-constant marker + break; + case 'x': + x = (int) ins.getAttrLong("num"); + assert (x >= 0 && x <= ((j == jlimit - 1) ? 0xFF : 0xFFFF)); + break; + case 's': + x = (int) ins.getAttrLong("num"); + if (x != (byte) x && j == jlimit - 1) { + switch (op) { + case 0x10: //bipush + ops[id] = (byte) (op = 0x11); //sipush + break; + case 0x84: //iinc + isWide[id] = true; + format = opFormat(op, isWide[id]); + break; + default: + assert (false); // cannot lengthen + } + } + // unsign the value now, to make later steps clearer + if (j == jlimit - 1) { + assert (x == (byte) x); + x = x & 0xFF; + } else { + assert (x == (short) x); + x = x & 0xFFFF; + } + break; + case 'o': + assert (branches[bn] == id); + bn++; + // make local copies of the branches, and fix up labels + insElems[id] = ins = new Element(ins); + String newLab = labels.get(ins.getAttr("lab")); + assert (newLab != null); + ins.setAttr("lab", newLab); + int prevCas = 0; + int k = 0; + for (Element cas : ins.elements()) { + assert (cas.getName().equals("Case")); + ins.set(k++, cas = new Element(cas)); + newLab = labels.get(cas.getAttr("lab")); + assert (newLab != null); + cas.setAttr("lab", newLab); + int thisCas = (int) cas.getAttrLong("num"); + assert (op == 0xab + || op == 0xaa && (k == 0 || thisCas == prevCas + 1)); + prevCas = thisCas; + } + break; + case 't': + // switch table is represented as Switch.Case sub-elements + break; + default: + assert (false); + } + operands[id] = x; // record operand (last if there are 2) + // skip redundant chars + while (j + 1 < jlimit && format.charAt(j + 1) == fc) { + ++j; + } + } + + switch (op) { + case 0xaa: //tableswitch + loc = switchBase(loc); + loc += 4 * (3 + ins.size()); + break; + case 0xab: //lookupswitch + loc = switchBase(loc); + loc += 4 * (2 + 2 * ins.size()); + break; + default: + if (isWide[id]) { + loc++; // 'wide' opcode prefix + } + loc += format.length(); + break; + } + } + insLocs[insCount] = loc; + + // compute branch offsets, and see if any branches need expansion + for (int maxTries = 9, tries = 0;; ++tries) { + boolean overflowing = false; + boolean[] branchExpansions = null; + for (int bn = 0; bn < branches.length - 1; bn++) { + int id = branches[bn]; + Element ins = insElems[id]; + int insSize = insLocs[id + 1] - insLocs[id]; + int origin = insLocs[id]; + int target = insLocs[(int) ins.getAttrLong("lab")]; + int offset = target - origin; + operands[id] = offset; + //System.out.println("branch id="+id+" len="+insSize+" to="+target+" offset="+offset); + assert (insSize == GOTO_LEN || insSize == GOTO_W_LEN || ins.getName().indexOf("switch") > 0); + boolean thisOverflow = (insSize == GOTO_LEN && (offset != (short) offset)); + if (thisOverflow && !overflowing) { + overflowing = true; + branchExpansions = new boolean[branches.length]; + } + if (thisOverflow || tries == maxTries - 1) { + // lengthen the branch + assert (!(thisOverflow && isWide[id])); + isWide[id] = true; + branchExpansions[bn] = true; + } + } + if (!overflowing) { + break; // done, usually on first try + } + assert (tries <= maxTries); + + // Walk over all instructions, expanding branches and updating locations. + int fixup = 0; + for (int bn = 0, id = 0; id < insCount; id++) { + insLocs[id] += fixup; + if (branches[bn] == id) { + int op = ops[id] & 0xFF; + int wop; + boolean invert; + if (branchExpansions[bn]) { + switch (op) { + case GOTO: //0xa7 + wop = GOTO_W; //0xc8 + invert = false; + break; + case 0xa8: //jsr + wop = 0xc9; //jsr_w + invert = false; + break; + default: + wop = invertBranchOp(op); + invert = true; + break; + } + assert (op != wop); + ops[id] = (byte) wop; + isWide[id] = invert; + if (invert) { + fixup += GOTO_W_LEN; //branch around a wide goto + } else { + fixup += (GOTO_W_LEN - GOTO_LEN); + } + // done expanding: ops and isWide reflect the decision + } + bn++; + } + } + insLocs[insCount] += fixup; + } + // we know the layout now + + // notify the caller of offsets, if requested + if (elemToIndexMap != null) { + for (int i = 0; i < elemToIndexMap.length; i++) { + int id = elemToIndexMap[i]; + if (id >= 0) { + Element ins = (Element) instructions.get(i); + ins.setAttr(pcAttrName, "" + insLocs[id]); + } + } + elemToIndexMap = null; // release the pointer + } + + // output the bytes + StringBuffer sbuf = new StringBuffer(insLocs[insCount]); + for (int bn = 0, id = 0; id < insCount; id++) { + //System.out.println("output id="+id+" loc="+insLocs[id]+" len="+(insLocs[id+1]-insLocs[id])+" #sbuf="+sbuf.length()); + assert (sbuf.length() == insLocs[id]); + Element ins; + int pc = insLocs[id]; + int nextpc = insLocs[id + 1]; + int op = ops[id] & 0xFF; + int opnd = operands[id]; + String format; + if (branches[bn] == id) { + bn++; + sbuf.append((char) op); + if (isWide[id]) { + // emit